dsh-deeppilot 0.9.4 → 0.9.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,143 @@
3
3
  > This is the durable audit record for DeepPilot's public DSH plugin. Re-audit
4
4
  > the next DSH release instead of assuming that an rc upgrade is runtime-safe.
5
5
 
6
- ## Current decision
6
+ ## Current decision — `dsh-v0.2.1-alpha.4`
7
+
8
+ - **Audited release:** `dsh-v0.2.1-alpha.4` (official release page:
9
+ <https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-alpha.4>),
10
+ published to npm 2026-10-15T13:08:08Z on the `alpha` dist-tag. It is **not**
11
+ `latest`; `latest`/`next` still point at `0.2.0-rc.2`, exactly as at alpha.3.
12
+ - **Comparison baseline:** `dsh-v0.2.1-alpha.3` (the previous audited tag).
13
+ - **Plugin runtime verdict: no break, and no `src/` change was needed.** Eight of
14
+ the ten peer packages ship a byte-identical `lib/` tree; only their
15
+ `package.json` `version` fields moved. That set includes `dsh-api-gateway`,
16
+ where alpha.3's first two breaks lived, and all three Client faces the resident
17
+ interaction client loads (`dsh-typert-registry/client`,
18
+ `dsh-client-connection/client`, `dsh-api-gateway/client`). Every alpha.3 fix
19
+ therefore still holds unchanged.
20
+ - **Only `dsh-api-remotes` changed in code, additively.** One new Remote Events
21
+ entry (`plugin-market/changed`) and the rename of `IncompatiblePlugin.peers` to
22
+ `requirements`. The plugin reads neither: it subscribes to no Remote Events
23
+ entry of that name, and its own phone-wire frame registry is a separate
24
+ vocabulary from DSH Remote Events. Its `lib/client.js` shows a 750-line diff
25
+ that normalises to zero contract changes — the bulk is `TYPERT_REMOTE$N`
26
+ renumbering plus `sourceLocation` line drift from the one inserted remote.
27
+ - **Two packages exist for the first time** — `@deepseek-ai/dsh-plugin-market`
28
+ and `@deepseek-ai/dsh-experimental-plugin-market-bundle` — behind this
29
+ release's custom plugin index sources. Neither is a dependency of this plugin,
30
+ the plugin does not name either in `inject`, and the bundle is a purely
31
+ additive entry in `dsh-app-boot`'s default bundle list.
32
+ - **Activation verdict: one break, and it is the release's own stated
33
+ migration.** alpha.4 changed the compatibility rule so that a plugin's own
34
+ `engines.dsh` range **decides alone and `peerDependencies` are ignored**
35
+ whenever that field is present; only a manifest without `engines.dsh` falls
36
+ back to the old peer evaluation. This plugin declared no `engines.dsh`, so it
37
+ kept the peer path, and its exact two-version peer list rejected
38
+ `0.2.1-alpha.4` — the plugin would not have activated on that host.
39
+ - **Evidence: reproduced against the published bundles, not inferred.** The audit
40
+ ran each host's own published `evaluatePluginCompatibility` (alpha.3 and
41
+ alpha.4 installed into separate isolated directories) against this plugin's
42
+ real `package.json`, over one candidate list. Before any edit, both hosts
43
+ admitted `0.2.0-rc.2` and `0.2.1-alpha.3` and both refused `0.2.1-alpha.4`,
44
+ reporting all ten peers unmet. With the new `engines.dsh` range in place, both
45
+ hosts admit all three audited releases; alpha.4 reports a **single**
46
+ `engines.dsh` requirement instead of ten peers when it refuses; and
47
+ `0.2.1-alpha.2`, `0.2.1-alpha.5`, `0.2.1`, and `0.3.0` are still refused.
48
+ alpha.3 ignores `engines.dsh` entirely — the field did not exist yet — and
49
+ keeps deciding on `peerDependencies`, which is why both declarations must name
50
+ the same list.
51
+ - **Install verdict: the two declarations now agree.** `engines.dsh` and all ten
52
+ `@deepseek-ai/dsh*` peers name `0.2.0-rc.2 || 0.2.1-alpha.3 || 0.2.1-alpha.4`,
53
+ mirrored in `tests/compatibility-metadata.test.ts`, `package-lock.json`, both
54
+ READMEs, `COMPATIBILITY.md`, `AGENTS.md`, and the local `docs/决策记录.md`
55
+ (章节一, 条目3). The dev pins and `DSH_BASELINE` stay at the exact
56
+ `0.2.0-rc.2` this branch builds and typechecks against.
57
+ - **Vendor peers need no widening.** Both hosts still vendor `cordis
58
+ 4.0.5-alpha.2` and `schemastery 3.18.5-alpha.2`; neither package published a
59
+ `dsh-0-2-1-alpha-4` dist-tag, and the existing `~4.0.5-alpha.1` /
60
+ `~3.18.5-alpha.1` ranges already admit them.
61
+ - **Protocol verdict: no phone-protocol change.** Protocol v2, pairing state, and
62
+ device records are untouched by this release; no phone needs to re-pair.
63
+ - **Unrelated to this plugin, recorded for completeness:** the release also
64
+ brought per-model reasoning levels for custom API models, discovery and
65
+ installation from custom plugin index sources, a command/argument input fix, an
66
+ Office file delivery change, a Developer Tools reload fix, lower Linux command
67
+ startup overhead, and failed-command status reporting. None of them touches a
68
+ surface this plugin calls.
69
+
70
+ ### Previous decision — `dsh-v0.2.1-alpha.3`
71
+
72
+ - **Audited release:** `dsh-v0.2.1-alpha.3` (official release page:
73
+ <https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-alpha.3>),
74
+ published to npm 2026-10-14T13:32:15Z on the `alpha` dist-tag. It is **not**
75
+ `latest`; `latest`/`next` still point at `0.2.0-rc.2`. Baseline commit
76
+ `2fbf4359b82fb94c03dcce0b831660d87f12ea5c`, compared against alpha.2's
77
+ `d743267388641bc76f17c45ce8b4c231aed1d32c` (**852 commits, 3311 changed files,
78
+ 120,978 insertions, 16,632 deletions**).
79
+ - **Comparison baseline:** `dsh-v0.2.1-alpha.2` (the previous audited tag).
80
+ - **Plugin runtime verdict: four confirmed breaks with one root cause — the
81
+ alpha.3 Peer model — and the resident interaction client does not start.**
82
+ **Fixed in this audit; see "The fix" below.**
83
+ This release makes every in-process carrier name a `PeerScope`
84
+ (`principal` / `signal` / `interactions`) explicitly; nothing defaults to the
85
+ operator any more. The four landing points, each with its own evidence:
86
+
87
+ | # | Upstream change | Plugin seam | Evidence |
88
+ | --- | --- | --- | --- |
89
+ | 1 | `TypertGatewayWireStream.open`'s 4th parameter `peer` is required; `assertPeerLive()` reads `peer.signal.aborted` before anything else | `src/dsh-remote-interactions.ts:180` passes `undefined, undefined` | Reproduced against the published bundles: alpha.2 returns normally, alpha.3 throws `TypeError: Cannot read properties of undefined (reading 'signal')` |
90
+ | 2 | `$events` additionally requires `peer.interactions === 'answer'` (`requireInteractions`) | same call | Reproduced: a peer with `interactions: 'none'` gets `gateway/interactions-forbidden`; a full owner/answer peer passes on **both** versions |
91
+ | 3 | `ConnectionFetchHandler.fetch(request, peer)` now takes a required Peer | `src/dsh-remote-interactions.ts:204` calls `fetchHandler.fetch(request)` | `lib/types/rpc.d.ts` declares `peer: PeerScope` required, "never defaulted" |
92
+ | 4 | `./client` gained `node`/`browser` conditions; Node now resolves `lib/client.node.js`, which carries **no** `window.__ModuleLoader__.load` banner | `loadClientFaces()` (`src/dsh-remote-interactions.ts:117`) builds its module table from that banner | `grep -c __ModuleLoader__` is 0 in `client.node.js`, 1 in `client.browser.js` and 1 in alpha.2's `client.js` |
93
+
94
+ A fifth, latent one: `installConnection` derives
95
+ `interactions ?? (location === undefined ? 'none' : 'answer')`, and the
96
+ plugin's Node context has no `location`, so `apply(ctx)` alone always selects
97
+ `'none'`. Passing an explicit Peer is not enough by itself — the install call
98
+ must name `interactions: 'answer'` too.
99
+ - **Failure mode is degradation, not a crash — but only partly contained.**
100
+ `src/dsh-api-proxy.ts:316` wraps `startDshRemoteInteractions` in `try/catch`
101
+ and logs `[deeppilot] DSH Remote interaction client unavailable`. Breaks 3 and
102
+ 4 surface while the resident client is being assembled, so they land in that
103
+ catch. Whether break 1/2 (the Gateway opens its Remote Events generation
104
+ asynchronously) also lands there is **not confirmed** — an uncaught rejection
105
+ there would be fatal under Node's default `--unhandled-rejections=throw`.
106
+ The phone loses approval/question delivery either way.
107
+ - **Fix direction (verified compatible with both hosted versions):** build one
108
+ owner/answer Peer (`new Peer(ownerCtx, { principal: { kind: 'owner' },
109
+ interactions: 'answer' })`, falling back to `connection.operator` on alpha.2)
110
+ and name it in every carrier call — alpha.2 ignores a second `fetch` argument
111
+ and defaults an absent `open` peer to the operator, so one call form serves
112
+ both. `loadClientFaces` additionally has to accept the Node bundle's named
113
+ exports when the banner did not fire; both shapes export `apply`/`inject`
114
+ (`installConnection`/`transportError` are extra on Node).
115
+ - **Install verdict: the peer range now names this release explicitly.** It moved
116
+ from the open-ended `>=0.2.0-rc.2 <0.3.0-0` to `0.2.0-rc.2 || 0.2.1-alpha.3`
117
+ across all ten `@deepseek-ai/dsh*` peers, and the two vendor peers widened to
118
+ `~4.0.4 || ~4.0.5-alpha.1` and `~3.18.4 || ~3.18.5-alpha.1`. Because DSH
119
+ evaluates that range on every start, the next DSH release deactivates this
120
+ plugin until the list is widened deliberately — see `docs/决策记录.md`
121
+ (章节一, 条目2), which records this as a reversal of the 2026-09-29 policy.
122
+ The published CLI composed the plugin's patch cleanly before the change (see
123
+ the 2026-10-14 entry). The plugin's own `lib/client.js` shape was not
124
+ re-verified against the alpha.3 client-modules scanner.
125
+ - **Protocol verdict: no phone-protocol change.** Protocol v2, pairing state,
126
+ and device records are untouched by this release; no phone needs to re-pair.
127
+ - **Two host-side migrations this machine must apply** (independent of the
128
+ plugin): `~/.dsh/profiles/web/cordis.patch.yml` carries
129
+ `llm-deepseek-account.config.models: []`, and alpha.3 throws on any residual
130
+ `models` key — **including an empty array** (`resolveAccountOptions`). Also
131
+ `dsh --profile <name> --from-default-profile <template>` now *replaces* an
132
+ existing profile directory (it deletes the old `node_modules` and
133
+ `cordis.patch.yml`); the audit procedure recorded below used that flag.
134
+ - **Capability gaps, not regressions:** the `contextBreakdown` projection was
135
+ reshaped (`nodes[]` → `systems[]` + `surfaceTokens` + `claim`, stateVersion
136
+ 5→6) and the plugin forwards it by key, so the phone may render empty values;
137
+ the model catalog shrank (account routes return only the version-gated
138
+ `offered` subset, pi-ai routes without a resolvable key return `[]`); and
139
+ `CLIENT_UPGRADE_REQUIRED` / `MODEL_UNSUPPORTED` are new codes with no mapping
140
+ in `src/wire-errors.ts` yet.
141
+
142
+ ### Previous decision — `dsh-v0.2.1-alpha.2`
7
143
 
8
144
  - **Audited release:** `dsh-v0.2.1-alpha.2` (official release page:
9
145
  <https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-alpha.2>),
@@ -43,9 +179,40 @@
43
179
 
44
180
  ### Plugin release verdicts
45
181
 
46
- - **Release verdict (`0.9.4`, prepared 2026-10-10, NOT published):** carries the
47
- `projections` adapter fix and the Automation tasks documentation correction
48
- described in the 2026-10-09 entry below. `package.json`, both root
182
+ - **发布结论(`0.9.5`,2026-10-15,`v0.9.5` @ `6517ad7`):** 包含 alpha.3
183
+ 对端(Peer)与客户端兼容修复、两个宿主精确列举策略、跨语言认证向量与恢复说明,
184
+ 以及手动 OIDC 身份认证与来源证明发布。包与锁文件两处根版本、基线快照一致。
185
+ - **发布前验证:** 干净依赖安装;562 项单元测试通过、零失败、一项既有待办;
186
+ 类型检查、构建、固定宿主的真实配置模型加载、Go 测试、六个辅助程序校验和与
187
+ 包内容检查通过。挑战篡改测试基于当前连接生成变更值,消除了时间碰撞,连续
188
+ 20 次重点回归通过。发布提交的持续集成(CI)和 CodeQL 代码安全扫描通过。
189
+ - **注册表与来源证明:** npm 于 `2026-10-14T23:29:29.605Z` 发布该版本,
190
+ `latest`(稳定分发标签)指向 `0.9.5`。下载压缩包共 50,934,088 字节,
191
+ SHA1 `6a2f356efa1e48849d9bf713f88cd0fd67c7999c` 与工作流上传记录一致;
192
+ SHA512 与注册表及来源证明中的包摘要一致。来源证明精确对应 `v0.9.5`、
193
+ `6517ad7b6d7022afc9b3d81d6779b434282c9c56` 和 `.github/workflows/publish.yml`。
194
+ `npm audit signatures`(npm 签名审计)通过,包含本插件的注册表签名和来源证明;
195
+ npm 可信发布者绑定显示 `Valid`(有效)。压缩包发布不依赖可选的 `gitHead`
196
+ 字段来确认源码,使用已验证签名的来源证明提交。
197
+ - **已发布包安装:** 两个独立的新 DSH 主目录分别使用 `0.2.0-rc.2` 与
198
+ `0.2.1-alpha.3`,从注册表执行 `dsh plugin --profile verify add dsh-deeppilot@0.9.5`。
199
+ 三条插件配置组合成功,版本为 `0.9.5`,安装路径未引用源码工作区,六个辅助程序
200
+ 校验和全部一致;实际配置模型导入未出现本插件相关错误。两个 Web 模板仍各有
201
+ 四项宿主配置模型错误,与未安装插件的基线完全一致;不把整个模板核对说成全绿。
202
+ - **真实宿主边界:** 隔离的 alpha.3 冒烟检查为 24 项通过、1 项失败、3 项跳过。
203
+ 失败项是未配置模型账号的全新主目录中,模型目录非空的断言;模型目录 RPC 正常
204
+ 且可路由。模型切换、真实提问和模型触发的审批问答未验证,iPhone 真机未验证。
205
+ 已认证连接重复提交认证证明的既有待办保留。
206
+ - **发布后缓存核对修正:** [首次发布运行](https://github.com/Mars-Sea/dsh-deeppilot/actions/runs/38653869533)
207
+ 上传成功,末尾核对短暂命中缓存的 404 而失败。独立注册表、摘要、签名及安装
208
+ 核验通过后才公开 [GitHub 发布页](https://github.com/Mars-Sea/dsh-deeppilot/releases/tag/v0.9.5)。
209
+ 后续仓库修正为刷新查询、要求元数据重新校验并最多读取重试 12 次;修正后的
210
+ 只读核对步骤已对真实注册表执行通过。未重跑上传、未修改已发布包或移动版本标签。
211
+ 发布说明:`docs/RELEASE_NOTES-0.9.5.md`。
212
+
213
+ - **Release verdict (`0.9.4`, published 2026-10-10, tag `v0.9.4` @ `e2f77af`):**
214
+ carries the `projections` adapter fix and the Automation tasks documentation
215
+ correction described in the 2026-10-09 entry below. `package.json`, both root
49
216
  `package-lock.json` version entries, and `tests/apply-baseline.snapshot.json`
50
217
  are on `0.9.4`, and `lib/` is regenerated. The full checklist passed locally:
51
218
  `npm ci`, 538 unit tests, typecheck, build, the config-schema check against a
@@ -53,9 +220,24 @@
53
220
  `npm pack --dry-run` (65 files, 50,916,470 bytes packed). The fix was also
54
221
  verified on a live `0.2.1-alpha.2` host against the published `0.9.3` as an
55
222
  A/B control (25 pass / 0 fail either way, with the `sessions.projections
56
- failed: internal` diagnostic present only on `0.9.3`). Nothing was
57
- published, tagged, or pushed; npm `latest` still points at `0.9.3`, so users on
58
- `0.2.1-alpha.2` keep hitting the projections defect until this ships.
223
+ failed: internal` diagnostic present only on `0.9.3`).
224
+ - **Registry verification after publishing.** `dist-tags.latest` moved off
225
+ `0.9.3`; `dist.shasum` `85b3c71a802e45e42f5fb1b23444ed2e396d39dc` is
226
+ byte-identical to the local `npm pack` output at the tag; 65 files,
227
+ `dist.unpackedSize` 130,789,604. **`gitHead` is `e2f77af`, the tag commit** —
228
+ the 0.9.3 ordering deviation did not repeat, because the release notes and
229
+ every other documentation change were committed before the pack. The publish
230
+ itself needed the maintainer's one-time password, as in 0.9.3; everything up
231
+ to and after it was done here.
232
+ - **Clean-profile verification.** A fresh isolated home, built from the shipped
233
+ Web template and installed with the published `0.2.1-alpha.2` CLI
234
+ (`dsh plugin --profile verify add dsh-deeppilot@0.9.4`), composed a real
235
+ profile: `--dump-config` printed the plugin's three rows
236
+ (`deeppilot-directory-picker-browse`, `…-browse-client`, `deeppilot`) with no
237
+ missing-module or load error, the installed package's six helper checksums
238
+ verified, every helper binary embedded `go1.26.9`, and the installed
239
+ `lib/index.js` carried the projections fix. Only then was the GitHub Release
240
+ taken out of draft and marked Latest.
59
241
  - **The release also had to fix the helper's toolchain and its refresh
60
242
  workflow.** CI's `govulncheck` job reported 11 reachable Go standard-library
61
243
  vulnerabilities for the pinned `go 1.26.6`; this is time-triggered, not
@@ -207,6 +389,355 @@
207
389
  bundle" below. The plugin needs no code change; the phone's copy now points
208
390
  at the bundle.
209
391
 
392
+ ## 2026-10-15 — audit of `dsh-v0.2.1-alpha.4`
393
+
394
+ `dsh-v0.2.1-alpha.4` reached npm on 2026-10-15T13:08:08Z, roughly 24 hours after
395
+ alpha.3, with the GitHub release following at 13:40:02Z. It is a small release —
396
+ two features, five fixes, and one compatibility-policy change — and
397
+ `latest`/`next` still point at `0.2.0-rc.2`.
398
+
399
+ ### Method
400
+
401
+ This audit established the change surface from **released artifacts before
402
+ reading any source**, rather than from the release notes, because those notes are
403
+ under 2 KB and all four of alpha.3's breaks had been invisible in its notes.
404
+ Every `@deepseek-ai/dsh*` peer package was fetched from npm at both
405
+ `0.2.1-alpha.3` and `0.2.1-alpha.4`, unpacked into a scratch tree, and compared
406
+ file by file. The one large diff was then re-compared after normalising
407
+ `TYPERT_REMOTE$N` renumbering and `sourceLocation` line/column drift, so that
408
+ mechanical churn could not hide a contract change.
409
+
410
+ ### Change surface
411
+
412
+ - **Eight of the ten peer packages carry a byte-identical `lib/` tree**:
413
+ `dsh-api-gateway`, `dsh-client-connection`, `dsh-client-locale`,
414
+ `dsh-client-ui-settings`, `dsh-client-ui-slots`, `dsh-settings`,
415
+ `dsh-typert-protocol`, `dsh-typert-registry`. Only their `package.json`
416
+ `version` fields moved. That set includes every module alpha.3 broke the
417
+ plugin through.
418
+ - **`dsh-api-remotes`** gained one Remote Events entry (`plugin-market/changed`),
419
+ renamed `IncompatiblePlugin.peers` to `requirements`, and added a
420
+ `pluginMarket` remote. Its `lib/client.js` diff spans 750 lines but normalises
421
+ to zero contract changes — `TYPERT_REMOTE$N` renumbering, `sourceLocation`
422
+ drift, and one rewritten `productAnalytics/report` description.
423
+ - **`dsh-app-boot`** rewrote the compatibility evaluator (below) and appended
424
+ `@deepseek-ai/dsh-experimental-plugin-market-bundle` to its default bundle
425
+ list, which is additive to `DEFAULT_BUNDLES`.
426
+ - **`dsh-plugin-manager`** carried the same `peers` → `requirements` rename
427
+ through `IncompatiblePlugin` and its diagnostics.
428
+ - **Two packages are new at this release**: `@deepseek-ai/dsh-plugin-market` and
429
+ `@deepseek-ai/dsh-experimental-plugin-market-bundle`. Neither resolves at
430
+ alpha.3. Neither is a dependency of this plugin, and neither appears in its
431
+ `inject`.
432
+ - The `dsh` CLI's own ten `@deepseek-ai/dsh*` dependencies all moved to alpha.4;
433
+ the vendor pins did **not** move. Both hosts still vendor `cordis
434
+ 4.0.5-alpha.2` and `schemastery 3.18.5-alpha.2`, and neither vendor published a
435
+ `dsh-0-2-1-alpha-4` dist-tag, so the existing `~4.0.5-alpha.1` /
436
+ `~3.18.5-alpha.1` ranges already admit what both hosts ship.
437
+
438
+ ### The one break: `engines.dsh` now decides alone
439
+
440
+ `dsh-app-boot`'s evaluator grew a requirements path that short-circuits the old
441
+ peer loop:
442
+
443
+ ```js
444
+ function unmetRequirements(fields, runtimeVersion) {
445
+ const engines = Object.hasOwn(fields, "engines") ? objectOf$1(fields.engines, "Plugin manifest engines") : {};
446
+ if (Object.hasOwn(engines, "dsh")) {
447
+ const range = engines.dsh;
448
+ if (typeof range !== "string") throw new Error("Plugin manifest engines.dsh must be a string");
449
+ return satisfies(runtimeVersion, range) ? {} : { "engines.dsh": range };
450
+ }
451
+ if (!Object.hasOwn(fields, "peerDependencies")) return {};
452
+ // ...otherwise the previous per-peer loop, unchanged
453
+ }
454
+ ```
455
+
456
+ Three consequences matter here. A plugin that declares `engines.dsh` is judged
457
+ **only** by it, and its `peerDependencies` are never read. A plugin that does not
458
+ declare it keeps the previous behaviour — which is the state this plugin was in,
459
+ so its exact two-version peer list refused `0.2.1-alpha.4`. And `engines.dsh` is
460
+ taken verbatim, with none of the `workspace:^` / `workspace:~` / `workspace:*`
461
+ substitution the peer path performs, so any `workspace:` range there is unmet.
462
+
463
+ ### Validation evidence
464
+
465
+ - **Compatibility decision, reproduced against the published evaluators — before
466
+ any edit.** Each host's own `evaluatePluginCompatibility` (alpha.3 and alpha.4,
467
+ installed into separate isolated directories) judged this plugin's real
468
+ `package.json` over one candidate list. Unchanged, both hosts admitted
469
+ `0.2.0-rc.2` and `0.2.1-alpha.3` and refused `0.2.1-alpha.4`, listing all ten
470
+ peers as unmet. With the added `engines.dsh` range, both hosts admit all three
471
+ audited releases; alpha.4 reports a **single** `engines.dsh` requirement
472
+ instead of ten peers when it refuses; and `0.2.1-alpha.2`, `0.2.1-alpha.5`,
473
+ `0.2.1`, and `0.3.0` remain refused. alpha.3 ignores `engines.dsh` entirely
474
+ and keeps deciding on `peerDependencies`, which is why both declarations must
475
+ name the same list.
476
+ - **Live A/B install on the published alpha.4 CLI — the evidence that matters.**
477
+ Under an isolated `DSH_HOME`, the **unchanged** package was rejected outright:
478
+ `dsh: installation rejected: Plugin dsh-deeppilot@0.9.5 is incompatible with
479
+ dsh 0.2.1-alpha.4: requirements {…ten peers…}`, `Exact-version exemption: not
480
+ active`, `dsh: nothing was installed`, exit 1. The **fixed** package installed
481
+ cleanly, exit 0, linked into the profile manifest's `dsh.profile.bundles`
482
+ alongside `@deepseek-ai/dsh-sdk-minimal`.
483
+ - **Composed tree:** the same CLI's `--dump-config` produced **162 rows with the
484
+ plugin and 153 without it**, the plugin's three rows present at
485
+ `deeppilot-directory-picker-browse`, `deeppilot-directory-picker-browse-client`,
486
+ and `deeppilot`, with no `skipped`/`incompatible` diagnostic. The single
487
+ warning is the `sdk-minimal` template's own missing `directory-picker` entry,
488
+ which alpha.3 recorded as well.
489
+ - **Live boot on a real alpha.4 Web host.** An isolated `DSH_HOME` profile built
490
+ from the shipped Web template and linked to this working tree booted under the
491
+ published alpha.4 CLI on `--port 3180` (the default 3080 is held by this
492
+ machine's own Host). The plugin started fully —
493
+ `[deeppilot] data plane active (mux + host streams)`,
494
+ `[deeppilot] LAN TLS identity created`,
495
+ `[deeppilot] local transport listening on https://0.0.0.0:3098` — and the
496
+ alpha.3 failure line `DSH Remote interaction client unavailable` **did not
497
+ appear**. A scan of the whole boot log for `incompatible`, `rejected`,
498
+ `requirements`, `unavailable`, or `error` returns nothing.
499
+ - **Plugin unit tests:** `npm test` → **564 tests, 563 pass, 0 fail, 1 todo**,
500
+ including the new `engines.dsh names the same closed host list as the peer
501
+ range` and the updated peer-range boundary test. `npm run typecheck` passes.
502
+ - **Build and schema:** `npm run build` passes and leaves `lib/` **byte-identical
503
+ to HEAD** — this fix changes no code, only declarations and documentation, so
504
+ no host's runtime behaviour can regress. `npm run check:config-schema` passes
505
+ against the pinned `0.2.0-rc.2` CLI (`/34 → $defs/config19`, volatile fields
506
+ pinned).
507
+ - **Environment note, not a defect:** `check:config-schema` shells out to
508
+ `npx --yes @deepseek-ai/dsh@0.2.0-rc.2`, and this machine's `~/.npm/_cacache`
509
+ contains root-owned files, so the default npm cache fails with `EPERM`. Running
510
+ it with `npm_config_cache` pointed at a writable directory passes, and the
511
+ unchanged HEAD build fails identically under the default cache, which is what
512
+ attributes the failure to the machine rather than to this change.
513
+
514
+ ### Evidence limits
515
+
516
+ Verified: install admission on alpha.4, profile composition, plugin startup, and
517
+ the full unit/typecheck/build/schema suite. **Not** verified here: a real iPhone
518
+ against this alpha.4 host, the Funnel transport, and a real model turn. The
519
+ phone-side contract is unchanged by this release — protocol v2, pairing state,
520
+ and device records are untouched, so no paired phone needs to re-pair — but that
521
+ is a source-level verdict, not a device run.
522
+
523
+ ## 2026-10-14 — audit of `dsh-v0.2.1-alpha.3`
524
+
525
+ ### Scope and method
526
+
527
+ Compared `dsh-v0.2.1-alpha.2...dsh-v0.2.1-alpha.3` (**852 commits, 3311 changed
528
+ files, 120,978 insertions, 16,632 deletions**) by fetching the new tag into the
529
+ existing blobless clone (`.audit-dsh-alpha2`, whose HEAD was already the alpha.2
530
+ audit's target SHA `d7432673`), then `git diff --name-status` and per-path
531
+ content diffs into `.audit-alpha3/diffs/`. Four parallel read-only passes
532
+ covered `packages/api` + `apps/cli` + `packages/typert` + `packages/settings` +
533
+ `vendor`, `packages/client/{connection,locale,ui-settings,ui-slots}` +
534
+ `packages/boot` + `packages/bundle`, `packages/{credentials,subagent,session,
535
+ schedule}`, and `packages/{core,host,skill,llm}`. All **14** upgrade guides
536
+ added by this release (under `docs/upgrade-guide/v0.2.0-rc.2/`,
537
+ `v0.2.1-alpha.1/`, `v0.2.1-alpha.2/`) were read in Chinese in full.
538
+
539
+ The alpha.2 audit's lesson — judge the seams reached through `ctx.get`, not just
540
+ the peer list — is what caught this one: the peer list is *not* where the breaks
541
+ are. `@deepseek-ai/dsh-api-remote-access` is new, `packages/schedule/schedule`
542
+ has **zero** changed source files, and the peer packages' own exported surfaces
543
+ moved far less than the carrier contracts around them.
544
+
545
+ ### The four confirmed breaks
546
+
547
+ Every one is the same root cause: alpha.3 makes the Peer explicit. `PeerScope`
548
+ (`@deepseek-ai/dsh-typert-protocol`) gained required `principal`, `signal`, and
549
+ `interactions`; `client/connection` added a `Peer` class and deleted
550
+ `OperatorPeer`; the Gateway deleted `operatorPeer()` and its
551
+ `request.peer ?? this.operatorPeer()` fallback.
552
+
553
+ Reproduction used the **published** bundles, the same technique as the alpha.2
554
+ `projections` break, with the plugin's exact argument list
555
+ (`open('$events', payload, undefined, peer, signal)`):
556
+
557
+ ```sh
558
+ # .audit-alpha3/repro-peer-contract.mjs, against
559
+ # alpha.2: ~/.npm/_npx/b5c6312874079fe8/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js
560
+ # alpha.3: .audit-alpha3/cli-install/node_modules/@deepseek-ai/dsh-api-gateway/lib/index.js
561
+ # A. peer = undefined (what the plugin sends today)
562
+ alpha.2: 未抛错
563
+ alpha.3: 抛错 TypeError: Cannot read properties of undefined (reading 'signal')
564
+ # B. peer = { principal: owner, signal, interactions: 'none' }
565
+ alpha.2: 未抛错
566
+ alpha.3: 抛错 TypertGatewayError: $events: forwarded Remote events require interactions=answer
567
+ # C. peer = { principal: owner, signal, interactions: 'answer' }
568
+ alpha.2: 未抛错
569
+ alpha.3: 未抛错
570
+ ```
571
+
572
+ Break 4 was settled by reading the shipped artifacts rather than by inference:
573
+ `@deepseek-ai/dsh-client-connection`'s `./client` now maps `node` →
574
+ `lib/client.node.js`, and that file contains **zero** `__ModuleLoader__`
575
+ occurrences while `client.browser.js` and alpha.2's `client.js` each contain
576
+ one. `loadClientFaces` builds its module table *only* from that banner, so on
577
+ Node the table stays empty. Both shapes export `apply` and `inject`, which is
578
+ what makes a banner-optional fallback possible.
579
+
580
+ ### The fix
581
+
582
+ One call form serves both audited hosts, because alpha.2 ignores a second
583
+ `fetch` argument and defaults an absent `open` peer to the operator Peer it
584
+ holds:
585
+
586
+ - `src/dsh-remote-interactions.ts` mints one Peer through
587
+ `connection.createPeer({ principal: { kind: 'owner' }, interactions: 'answer' })`
588
+ and falls back to `connection.operator` on a Host without that entry point.
589
+ The same Peer is named on `fetch` and on `wireStream.open`.
590
+ - The Connection install prefers the explicit
591
+ `installConnection(ctx, { transport, interactions: 'answer' })`, because
592
+ `apply(ctx)` cannot name the participation and therefore always selects
593
+ `'none'` for this caller; `apply` remains the fallback for a host that predates
594
+ the installer.
595
+ - `loadClientFaces` accepts a Node bundle's named exports when the browser
596
+ banner did not register them. A banner registration still wins, because the
597
+ bundle's own internal `require()` resolves against it.
598
+
599
+ Six regression tests in `tests/dsh-wire-stream-contract.test.ts` pin the
600
+ contract: the operator fallback, the alpha.3 `createPeer` request shape and the
601
+ Peer reaching `wireStream.open`, both installer branches, and both module-table
602
+ branches. The file fails against the previous call form — verified by restoring
603
+ the source and re-running (1 failure) — and passes after the fix.
604
+
605
+ ### Peer range narrowed to the two audited hosts
606
+
607
+ By explicit user direction the DSH peer range stopped being open-ended:
608
+ `>=0.2.0-rc.2 <0.3.0-0` became `0.2.0-rc.2 || 0.2.1-alpha.3` across all ten
609
+ `@deepseek-ai/dsh*` peers, with `@deepseek-ai/cordis` widened to
610
+ `~4.0.4 || ~4.0.5-alpha.1` and `@deepseek-ai/schemastery` to
611
+ `~3.18.4 || ~3.18.5-alpha.1`. The two vendor peers are outside DSH's own peer
612
+ check — it reads only `@deepseek-ai/dsh` and `@deepseek-ai/dsh-*` — so their
613
+ ranges matter only to npm's install-time resolution, which runs without
614
+ `includePrerelease`; naming both vendored prereleases keeps a clean install on
615
+ either host. `devDependencies` stay pinned to `0.2.0-rc.2`.
616
+
617
+ The consequence is deliberate: `evaluatePluginCompatibility` runs before a
618
+ profile is composed on every start, so the next DSH release will refuse to
619
+ activate this plugin until the list is widened by an audit. That reversal of the
620
+ 2026-09-29 policy is recorded in `docs/决策记录.md` (章节一, 条目2).
621
+ `tests/compatibility-metadata.test.ts` now asserts both admissions, fifteen
622
+ rejections, and the two vendor ranges.
623
+
624
+ ### Host-side changes with no plugin impact
625
+
626
+ `packages/schedule/schedule/**` has no changed source; the schedule error-code
627
+ table is identical, so `src/wire-errors.ts`'s twelve mappings (including
628
+ `subagent_session → E_PROTOCOL`) stay correct. No session-log format migration
629
+ exists — `session-format*`, `v0-to-v1`…`v3-to-v4`, `session-persistence`,
630
+ `session-projection*`, `session-log-deepseek` changed only their version and
631
+ locale files — so phone history rendering is unaffected. The subagent descriptor
632
+ is still version 3. `host/webserver`'s `port` widening, the macOS directory
633
+ picker, the PTC call registry, and the new `job/registered` / `job/settled`
634
+ events are all unreachable or safely skipped by this plugin (`projectEvent`'s
635
+ `default: return null`). Settings surfaces are unchanged at the contract level:
636
+ `ui-settings`'s `settings.section` slot has the same SHA as alpha.2, and
637
+ `configForms.get()` kept its name. The Web composition still mounts
638
+ `schedule`/`ui-schedule`, and `directory-picker` is still disabled in place, so
639
+ the plugin's three `cordis.patch.yml` rows still land.
640
+
641
+ ### Validation evidence
642
+
643
+ - **Config schema on the published CLI:** isolated `DSH_HOME`, `dsh
644
+ --profile deeppilot-audit --from-default-profile sdk-minimal
645
+ --dump-config-schema --patch cordis.patch.yml` against
646
+ `@deepseek-ai/dsh@0.2.1-alpha.3` → exit 0, 179,851 bytes, the plugin entry at
647
+ `/37` reports `status: 'schema'` with `configRef: #/$defs/config24`, all seven
648
+ volatile assertions pass, no `deeppilot`-attributed diagnostic, and the only
649
+ warning is the `sdk-minimal` template's own missing `directory-picker` row.
650
+ - **Web composition:** the same CLI composed a real Web profile with the plugin
651
+ patch → **1225 rows versus 1214 without it**, the plugin's three rows present
652
+ at `deeppilot-directory-picker-browse` / `…-browse-client` / `deeppilot`, and
653
+ zero `unrecognized Loader tree carrier` entries on either side.
654
+ - **Plugin unit tests:** `npx tsx --test tests/*.test.ts` → **562 tests, 561
655
+ pass, 0 fail, 1 todo**, including the six new contract tests. `npm run
656
+ typecheck`, `npm run build`, and `npm run check:config-schema` (against the
657
+ pinned `0.2.0-rc.2` CLI) all pass with regenerated `lib/`.
658
+ - **Live A/B on a real `0.2.1-alpha.3` host — the evidence that matters.** An
659
+ isolated `DSH_HOME` profile built from the shipped Web template and linked to
660
+ this working tree booted under the published alpha.3 CLI (`--port 3180`; the
661
+ default 3080 was already held by this machine's own Host). The **unfixed**
662
+ `0.9.4` build printed
663
+ `[deeppilot] DSH Remote interaction client unavailable:
664
+ @deepseek-ai/dsh-typert-registry/client Client bundle returned no exports`
665
+ and the fixed build printed no such line. The checklist itself scored
666
+ **23 pass / 1 fail / 4 skipped in both runs** — see the blind spot below.
667
+ - **The regression checklist does not cover this seam.** `scripts/smoke-live.mts`
668
+ scored identically before and after the fix, because the resident Client it
669
+ exercises is only reachable through the approval/question waterfall, and step
670
+ 10 is skipped without `--interactions`. The observable difference is the Host
671
+ log line and the phone's approval/question delivery, not a checklist step. A
672
+ future revision should assert on that diagnostic directly.
673
+ - **Backward compatibility, same working tree:** the same profile booted under
674
+ the published `0.2.1-alpha.2` CLI (`--port 3181`) scored **25 pass / 0 fail /
675
+ 0 warn / 3 skipped** with no interaction-client diagnostic — the same result
676
+ the alpha.2 audit recorded, so the fix does not regress the host users run
677
+ today.
678
+ - **One checklist difference between the two host versions is real.**
679
+ `模型目录可读` passes on alpha.2 and fails on alpha.3 in the same isolated
680
+ home (`0 provider / 0 model, routable=true`): this release stops listing a
681
+ pi-ai route before its credential resolves and returns only the version-gated
682
+ subset for the account route. The home has no model credential, so the phone's
683
+ model list is empty there. That is the documented behavior change, not a
684
+ plugin defect.
685
+ - **Artifact inspection:** the `node`/`browser` conditional exports and the
686
+ banner counts above were read from the installed alpha.3 packages, not from
687
+ the diff.
688
+
689
+ ### Host-side migrations this machine must apply
690
+
691
+ Neither is a plugin defect, and neither is fixed by the plugin change:
692
+
693
+ 1. **`llm-deepseek-account`'s retired `models` key.**
694
+ `~/.dsh/profiles/web/cordis.patch.yml:77-79` sets `models: []`.
695
+ `resolveAccountOptions` throws for *any* own `models` key
696
+ (`llm-deepseek-account: models is no longer configurable…`), and the
697
+ upstream test pins `[{ models: [] }, /models is no longer configurable/]`.
698
+ The empty array is not exempt. The `desktop` profile's row carries no
699
+ `config` and is unaffected. Whether the throw takes the whole Host down or
700
+ only retires that route was **not** measured — the guide says the account
701
+ models stop appearing either way.
702
+ 2. **`--from-default-profile` now replaces.** It stages a fresh copy over the
703
+ target and deletes the previous directory, including `node_modules` and the
704
+ user's own `cordis.patch.yml`. The re-audit procedure below and the alpha.2
705
+ entry's schema command both use that flag; from now on it must be pointed at
706
+ a scratch name.
707
+
708
+ Checked and **not** required: Azure provider rename (no `azure` /
709
+ `azure-openai-responses` key exists under `~/.dsh/profiles`), credential-file
710
+ extra keys (the file's top level is already `version`/`refs`/`records`), and
711
+ the stored-credential precedence flip (no `refs` name is exported in the shell,
712
+ and the stored value won precedence over `.env` on both sides of the change).
713
+
714
+ ### Still unverified
715
+
716
+ - Whether breaks 1 and 2 surface inside `dsh-api-proxy.ts`'s catch or escape it
717
+ as an unhandled rejection — the Gateway opens its Remote Events generation
718
+ asynchronously, after `startDshRemoteInteractions` has already returned.
719
+ - Whether an old profile that predates `@deepseek-ai/dsh-api-remote-access`
720
+ still gets the row (the shipped Web template does; `dsh-base` carries it).
721
+ - How the reshaped `contextBreakdown` renders on iOS, and what the phone shows
722
+ for the unmapped `CLIENT_UPGRADE_REQUIRED` / `MODEL_UNSUPPORTED` codes.
723
+ - Whether the plugin's own `lib/client.js` (banner shape, `dsh.client.inject`,
724
+ `platform: web`) is still accepted by alpha.3's client-modules scanner; that
725
+ scanner lives in `packages/client/modules` and `packages/client/web`, which
726
+ were not read in full.
727
+
728
+ ### Re-audit procedure used
729
+
730
+ Fetch the new tag into the existing blobless clone at `.audit-dsh-alpha2`
731
+ (`git fetch --filter=blob:none --no-tags origin
732
+ '+refs/tags/<tag>:refs/tags/<tag>'`, ~3 s), slice
733
+ `git diff --name-status` per package, and write each slice's content diff to a
734
+ file before parallel reading — blobless clones fetch blobs on demand, so one
735
+ `git diff` per region is far cheaper than many small reads. Reproduce a
736
+ suspected carrier break against the **published** `lib/` bundles with a stub
737
+ `this`, as above, rather than trusting either the diff or the release notes.
738
+ `npm --cache <workspace dir>` is still required; `~/.npm/_cacache` holds
739
+ root-owned files and fails `npm view` with `EPERM`.
740
+
210
741
  ## 2026-10-09 — audit of `dsh-v0.2.1-alpha.2`
211
742
 
212
743
  ### Scope and method
@@ -316,12 +847,12 @@ the mirror's `signal` is required, so the compiler keeps it that way.
316
847
  own, so a dedicated long-lived controller is not warranted; following the
317
848
  existing convention in the same file is enough. `lib/index.js` was regenerated.
318
849
 
319
- The fix ships in `0.9.4`, which is prepared but not published (see "Plugin release
320
- verdicts"); until it is published, a host on `0.2.1-alpha.2` running the
321
- published `0.9.3` still loses the on-open projection baseline. That was observed
322
- directly: on a live `0.2.1-alpha.2` host running published `0.9.3` the diagnostic
323
- appeared, and on the same host version running this build it did not (see "Live
324
- run on a real `0.2.1-alpha.2` host" under Validation evidence).
850
+ The fix ships in `0.9.4`, published 2026-10-10 (see "Plugin release verdicts").
851
+ A host on `0.2.1-alpha.2` left on the published `0.9.3` still loses the on-open
852
+ projection baseline. That was observed directly: on a live `0.2.1-alpha.2` host
853
+ running published `0.9.3` the diagnostic appeared, and on the same host version
854
+ running this build it did not (see "Live run on a real `0.2.1-alpha.2` host"
855
+ under Validation evidence).
325
856
 
326
857
  `tests/dsh-api-proxy.test.ts` adds "projection baseline reads pass the
327
858
  AbortSignal the Host now requires": a controller stub that calls