The contract and verifier are now connected to the current Market install service. Catalog entries with a pinned GitHub source are verified before Profile checks, receive their package identity from the pinned manifest, and execute only the constructed github target through the existing package-manager capability. Npm candidates retain their existing path.\n\nConstraint: Profile checkpoint recovery remains the next boundary; this commit does not invent a second WAL\nRejected: Keep GitHub entries manual-only | it would leave the current catalog contract unable to serve the user workflow\nConfidence: medium\nScope-risk: broad\nDirective: Add checkpoint-backed rollback and live Market adapter emission before treating GitHub installation as release-ready\nTested: 13 focused Market install/verifier tests, Market typecheck\nNot-tested: Live GitHub install, rollback after pnpm mutation, packaged Desktop run
The install contract needs a Host-owned verifier before any GitHub source can reach pnpm. Fetch package.json from the exact raw.githubusercontent.com commit path, reject redirects and malformed DSH metadata, and construct the pinned target without accepting provider command text.\n\nConstraint: No automatic installation is wired in by this commit\nRejected: Trust the catalog repository and commit claims alone | the package manifest and bundle declaration still need independent verification\nConfidence: medium\nScope-risk: moderate\nDirective: Integrate this verifier with the Market intent and Profile checkpoint path before exposing a mutating action\nTested: 6 focused GitHub verifier tests, Market typecheck, diff check\nNot-tested: Live GitHub access and pnpm installation
The current Market can already show a Host-derived manual install command when managed installation is unavailable. Reuse the new pinned source contract to expose a credential-free GitHub command without granting the Renderer or provider executable authority.\n\nConstraint: This commit does not enable automatic GitHub installation\nRejected: Show the provider's raw install command | provider text is not execution authority\nConfidence: high\nScope-risk: narrow\nDirective: Keep mutable HEAD-based GitHub hints separate from pinned commit sources\nTested: 21 Market contract/manual-hint tests, Market typecheck, diff check\nNot-tested: GitHub source resolution or package installation
A commit pin alone is insufficient when the catalog repository is missing, non-GitHub, or ambiguous. Normalize the repository first, derive owner and repository names from the canonical URL, and reject invalid source descriptors during both provider-page and snapshot parsing.\n\nConstraint: Providers remain unable to supply commands, credentials, or filesystem paths\nRejected: Validate only the installSource object | it would allow a commit to be paired with a different repository\nConfidence: high\nScope-risk: narrow\nDirective: Reuse this normalized identity when the Host-owned install executor is added\nTested: 19 catalog contract tests, Market typecheck, diff check\nNot-tested: GitHub network verification and package installation
Catalog providers need a structured source identity before Desktop can safely support GitHub and monorepo installs. This additive contract records a GitHub kind and a full commit SHA without granting the provider executable package-manager input.\n\nConstraint: Existing catalog entries remain valid and install behavior stays unchanged\nRejected: Reuse repository URLs as executable targets | repository identity does not pin content or authorize installation\nConfidence: high\nScope-risk: moderate\nDirective: Keep install execution behind a separate Host-owned verification boundary\nTested: Generated contract types and schema compilation\nNot-tested: Provider adapters emitting installSource values
The Host session catalog previously discarded adapter-owned input modalities, so downstream Desktop consumers could not distinguish image-capable routes even when the provider declared them. Patch the exact published rc.2 bundle and keep schema, runtime projection, and public types aligned.
Constraint: Desktop consumes the published Host bundle and must not modify the pinned Harness submodule.
Rejected: Add model selection or attachment UI here | those are separate presentation concerns from the catalog contract.
Confidence: high
Scope-risk: narrow
Directive: Remove this patch when a future Host release preserves inputModalities natively.
Tested: focused package surface 32 passed, 1 skipped; schema behavior; full yarn check with Market 274 and Desktop 808 passed, 4 skipped; immutable install; three safety review rounds.
Not-tested: Live DeepSeek API catalog response against a packaged Desktop build.
Related: #460, #470
Keep the main shell under generation-owned reveal control, but surface it before ready-to-show so users can see startup progress. Opaque shells now start on the same dark background used by the boot surface, while renderer health and recovery gating stay on their existing path.
Constraint: Perceived startup needed improvement without weakening renderer failure and recovery behavior
Rejected: BrowserWindow show:true at construction | would bypass generation-owned reveal timing and listener setup
Directive: Keep renderer-health acceptance tied to native mount completion; early reveal must stay a presentation-only change
Confidence: high
Scope-risk: narrow
Tested: corepack yarn workspace dsh-plugin-desktop exec vitest run tests/window-options.spec.ts tests/electron-runtime.spec.ts tests/profile-create-window.spec.ts tests/startup-recovery-window.spec.ts
Tested: corepack yarn workspace dsh-plugin-desktop exec vitest run tests/renderer-health.spec.ts
Tested: corepack yarn typecheck
Tested: corepack yarn build
Tested: git diff --check
Not-tested: Manual macOS/Windows startup visual verification in a real Electron session
Issue #427 calls for plugin-author guidance that matches the current
Desktop public contract instead of ambient profile guesses or unmanaged
package-manager lifetimes. The guide now keeps the Desktop adapter in one
nested injection, describes the external `dsh web` mirror recipe, and
records the bilingual pair through the repository hash gate.
Constraint: Public plugin-author guidance must stay within desktopProfiles and desktopPnpm
Rejected: Document guessed `profiles/web` and ambient `pnpm` flows | they bypass the Desktop-selected profile and managed lifecycle
Directive: Keep this recipe scoped to external `dsh web` mirrors; native Electron verification still belongs in real Desktop runs
Confidence: high
Scope-risk: narrow
Tested: corepack yarn test:bilingual-docs
Tested: corepack yarn check:bilingual-docs
Tested: corepack yarn check
Recurring startup and plugin reports lack the comparison data needed to distinguish upgraded Profile state from built-in Desktop behavior. Require reporters to identify Profile provenance, list third-party plugins, and record a fresh-Profile comparison while preserving a clear not-tested path.
Constraint: The form must remain usable when Desktop cannot start.
Rejected: Require diagnostic commands for every report | startup failures may prevent collection.
Confidence: high
Scope-risk: narrow
Directive: Keep the not-tested and no-plugin options when refining these fields.
Tested: YAML structure validation; layout checks; 1064 tests; typecheck; production build; three change-scoped safety inspections.
Not-tested: Live GitHub issue-form rendering before PR preview.
The Desktop launcher now checks the persisted session projection cache before the harness boots. If the cache file is already far beyond normal rebuilt sizes, Desktop moves it aside so startup can rebuild projections from session history instead of loading a file large enough to trigger V8 heap exhaustion.
The recovery lives in the launcher boundary because this repository treats the upstream DeepSeek Harness checkout as pinned and unmodified from desktop feature branches. The regression test uses a tiny synthetic file with a lowered threshold, which proves the quarantine path without manufacturing an actual OOM case.
Constraint: The pinned deepseek-harness submodule must remain unchanged from this desktop branch
Rejected: Patch the upstream session projection cache implementation in the submodule | repository rules forbid desktop-branch edits there
Rejected: Keep the fix as a best-effort warning only | continuing startup with a known oversized cache would not reliably avoid the OOM
Confidence: high
Scope-risk: narrow
Directive: Keep this preflight at the launcher boundary unless the upstream runtime gains its own durable projcache compaction or guardrail
Tested: corepack yarn workspace dsh-plugin-desktop exec vitest run tests/session-projcache-recovery.spec.ts
Tested: corepack yarn workspace dsh-plugin-desktop exec vitest run tests/package.spec.ts
Tested: corepack yarn workspace dsh-plugin-desktop typecheck
Tested: corepack yarn workspace dsh-plugin-desktop build
Desktop ships the published token-meter package, and that package can persist negative projection totals after compaction drift. Clamp the two O(1) totals and bump their state versions so existing bad cache rows are invalidated and rebuilt from the session log instead of failing history restore.
Constraint: deepseek-harness is a pinned submodule and must stay untouched on desktop branches
Rejected: Patch SessionProjectionRegistry checkpoint validation only | does not self-heal already persisted bad rows
Rejected: Edit deepseek-harness directly | repository policy requires Desktop fixes through the patch layer
Confidence: high
Scope-risk: narrow
Directive: Remove this Desktop token-meter patch once a published @deepseek-ai/dsh-token-meter release includes the clamp and state-version bump
Tested: corepack yarn workspace dsh-plugin-desktop test tests/token-meter-negative-projection.spec.ts
Tested: corepack yarn workspace dsh-plugin-desktop typecheck
Tested: corepack yarn workspace dsh-plugin-desktop build
Tested: corepack yarn install --immutable
Not-tested: Full workspace test suite
Not-tested: Packaged desktop smoke
Desktop ships upstream rc packages through Yarn patch resolutions, so the empty-name guard belongs in the patched agent loop rather than in a desktop-only wrapper. The new regression loads the installed loop implementation, exercises an empty-name tool call directly, and proves the turn now ends after one synthetic error with new-session guidance instead of entering normal unknown-tool dispatch.
Constraint: Desktop consumes upstream Harness rc packages through local Yarn patches
Rejected: Patch dsh-llm-deepseek again | adapter already preserves prior non-empty tool-call deltas, but finalized empty names still need loop-level termination
Rejected: Treat all unknown tools as terminal | would broaden behavior beyond the proxy-corruption case from issue #157
Confidence: high
Scope-risk: narrow
Directive: Keep the empty-name guard in the agent loop until upstream ships an rc that closes the loop at source
Tested: yarn workspace dsh-plugin-desktop vitest run tests/empty-tool-call-loop.spec.ts
Tested: yarn workspace dsh-plugin-desktop vitest run tests/deepseek-streaming-tool-call.spec.ts tests/empty-tool-call-loop.spec.ts
Tested: yarn workspace dsh-plugin-desktop vitest run tests/package.spec.ts -t 'patches the agent loop to stop after one empty-name tool call'
Tested: yarn workspace dsh-plugin-desktop typecheck
Tested: yarn workspace dsh-plugin-desktop build
The dialog integration test asserted macOS-only chrome while the shared check job runs on Linux. Keep this test focused on the cross-platform modal and hardened renderer contract; auxiliary-window tests retain platform-specific chrome coverage.
Constraint: The primary check workflow executes Desktop tests on Linux.
Rejected: Force process.platform in the integration test | it would hide the behavior of the platform actually running CI.
Confidence: high
Scope-risk: narrow
Directive: Keep platform-specific chrome assertions in auxiliary-window-options.spec.ts.
Tested: Focused dialog-window tests (3/3); full yarn check (81 Desktop files, 805 tests passed, 4 skipped; 274 Market tests); layout, runtime closure, licenses.
Not-tested: Windows runner; no production code changed.