dsh-deeppilot 0.9.1 → 0.9.3

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.
@@ -5,6 +5,68 @@
5
5
 
6
6
  ## Current decision
7
7
 
8
+ - **Audited release:** `dsh-v0.2.1-alpha.1` (official release page:
9
+ <https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.1-alpha.1>),
10
+ published 2026-10-03 on the npm `alpha` dist-tag. It is **not** `latest`;
11
+ `latest`/`next` still point at `0.2.0-rc.2`, which is what the current Host runs.
12
+ - **Comparison baseline:** `dsh-v0.2.0-rc.2` (the previous plugin baseline).
13
+ - **Plugin runtime verdict:** **no breaking change in the DSH APIs that DeepPilot
14
+ currently calls.** All 12 peer packages have **zero** changed `src/` files
15
+ between the two tags — each changed only its `package.json` version field and
16
+ its READMEs. See the 2026-10-03 entry below for the full finding-by-finding
17
+ table and for the three official upgrade guides checked against this plugin.
18
+ - **Nothing was changed to support this release.** `package.json`,
19
+ `package-lock.json`, generated `lib/`, `COMPATIBILITY.md`, and `PROTOCOL.md`
20
+ deliberately still describe the `0.2.0-rc.2` baseline. The release-audit-only
21
+ scope was agreed before the audit ran, so no version bump, no dependency
22
+ install, and no `lib/` regeneration was performed.
23
+ - **Peer range still admits it:** `>=0.2.0-rc.2 <0.3.0-0` satisfies
24
+ `0.2.1-alpha.1` under `semver.satisfies(..., { includePrerelease: true })`,
25
+ which is how DSH's `evaluatePluginCompatibility` gates activation. The same
26
+ holds for the `~4.0.4` / `~3.18.4` vendor ranges against `4.0.5-alpha.1` /
27
+ `3.18.5-alpha.1`. Under npm's **default** prerelease handling those three do
28
+ not match, so installing on an alpha host from npm reports peer warnings.
29
+ - **Protocol verdict:** no required DeepPilot phone-protocol break. Protocol v2,
30
+ pairing state, and device records are unchanged; already-paired phones need no
31
+ action.
32
+ - **Release verdict (`0.9.2`, published 2026-10-05, tag `v0.9.2` @ `4b43671`):**
33
+ shipped to `latest`. Verified on the registry: version present, `dist-tags.latest`
34
+ moved off `0.9.1`, `gitHead` `4b436715` matches the tag and HEAD, 65 files,
35
+ and a clean DSH profile install of `dsh-deeppilot@0.9.2` composes with the
36
+ plugin's three `cordis.patch.yml` entries present and no missing-module error.
37
+ `scripts/smoke-live.mts` passed with **0 failures** against a live
38
+ **`dsh-v0.2.1-alpha.1`** web profile — the first live-host verification since
39
+ the 0.9.1 entry, retiring the gate it left open ("pending separate
40
+ authorization before the `0.9.1` release ships"), on a newer host than the
41
+ rc.2 that entry contemplated, which is strictly stronger evidence: the
42
+ `0.2.1-alpha.1` source-diff above found zero changed `src/` files across all
43
+ 12 peer packages, and the live run agrees. The plugin's own build and type
44
+ baselines stay pinned to `0.2.0-rc.2`; nothing about the pin changed.
45
+ - **Install caveat users will hit — DSH's release-age policy.** On a clean
46
+ profile, `dsh plugin add dsh-deeppilot` installed **`0.9.1`**, not the just
47
+ published `0.9.2`, even though `latest` already pointed at `0.9.2`. DSH
48
+ deliberately prefers a slightly older release and offers an exact-version
49
+ path instead; `dsh plugin add dsh-deeppilot@0.9.2` installs the new one.
50
+ This is expected DSH behaviour, not a publishing failure — do not read the
51
+ older version in the installer as a broken release.
52
+ - **Peer-range note for future audits.** `evaluatePluginCompatibility` checks
53
+ each peer against the *running DSH version*, but `cordis` and `schemastery`
54
+ are host-vendored third parties and `react` comes from the Web app. Judging
55
+ those three against a DSH version number reports false mismatches. They are
56
+ also `optional` in `peerDependenciesMeta`. Confirm installability by
57
+ composing a real profile, not by iterating the peer table.
58
+ - **Two tracked follow-ups:**
59
+ 1. **Schedule documentation is now stale.** Automation tasks became a
60
+ built-in Web capability and `@deepseek-ai/dsh-experimental-schedule-bundle`
61
+ is in DSH's new `RETIRED_BUNDLES` set, so the user instruction "enable
62
+ Automation tasks in the plugin manager" points at a retired bundle.
63
+ Affects `PROTOCOL.md`, `COMPATIBILITY.md`, and the iOS copy. **Open.**
64
+ 2. ~~`subagent_session` is unmapped.~~ **Resolved 2026-10-03:** mapped to
65
+ `E_PROTOCOL` in `src/wire-errors.ts` and added to the frozen expectation in
66
+ `tests/wire-errors.test.ts`. 525 unit tests, typecheck, and build pass.
67
+
68
+ ### Previous decision — `dsh-v0.2.0-rc.2`
69
+
8
70
  - **Audited release:** `dsh-v0.2.0-rc.2` (official release page:
9
71
  <https://github.com/deepseek-ai/deepseek-harness/releases/tag/dsh-v0.2.0-rc.2>).
10
72
  - **Comparison baseline:** `dsh-v0.2.0-rc.1` (the previous plugin baseline).
@@ -27,6 +89,9 @@
27
89
  against the new range. The one remaining release-only step is a live
28
90
  `scripts/smoke-live.mts` run on a real rc.2 host, pending separate
29
91
  authorization before the `0.9.1` release ships.
92
+ **Closed 2026-10-04:** that gate was discharged by the `0.9.2` live run
93
+ instead — see the release verdict in "Current decision" above. It ran on
94
+ `0.2.1-alpha.1` rather than rc.2, which supersedes this entry's intent.
30
95
  - **Protocol verdict:** no required DeepPilot phone-protocol break. Protocol v2,
31
96
  pairing state, and device records are unchanged; already-paired phones need no
32
97
  action.
@@ -35,6 +100,158 @@
35
100
  bundle" below. The plugin needs no code change; the phone's copy now points
36
101
  at the bundle.
37
102
 
103
+ ## 2026-10-03 — audit of `dsh-v0.2.1-alpha.1`
104
+
105
+ ### Scope and method
106
+
107
+ Compared `dsh-v0.2.0-rc.2...dsh-v0.2.1-alpha.1` (**266 commits, 4190 changed
108
+ files**) from a fresh blobless clone
109
+ (`git clone --filter=blob:none --no-checkout`), unshallowed before measuring.
110
+ Package names were mapped to monorepo paths by reading every `package.json`
111
+ through a sparse checkout, then each package's `src/` was diffed with
112
+ `git diff --name-status`. Baseline SHA `639ed015`, target SHA `5badb150`.
113
+
114
+ ### Peer packages: 12 of 12 have zero changed source
115
+
116
+ Every peer package this plugin declares in `package.json` changed **only** its
117
+ `package.json` and its READMEs. No `src/` file moved:
118
+
119
+ | Package | Path | Version | Changed `src/` files |
120
+ | --- | --- | --- | --- |
121
+ | `@deepseek-ai/dsh` | `apps/cli` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
122
+ | `@deepseek-ai/dsh-api-gateway` | `packages/api/gateway` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
123
+ | `@deepseek-ai/dsh-api-remotes` | `packages/api/remotes` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
124
+ | `@deepseek-ai/dsh-client-connection` | `packages/client/connection` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
125
+ | `@deepseek-ai/dsh-client-locale` | `packages/client/locale` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
126
+ | `@deepseek-ai/dsh-client-ui-settings` | `packages/client/ui-settings` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
127
+ | `@deepseek-ai/dsh-client-ui-slots` | `packages/client/ui-slots` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
128
+ | `@deepseek-ai/dsh-settings` | `packages/settings/settings` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
129
+ | `@deepseek-ai/dsh-typert-protocol` | `packages/typert/protocol` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
130
+ | `@deepseek-ai/dsh-typert-registry` | `packages/typert/registry` | `0.2.0-rc.2` → `0.2.1-alpha.1` | 0 |
131
+ | `@deepseek-ai/cordis` | `vendor/cordis` | `4.0.4` → `4.0.5-alpha.1` | 0 |
132
+ | `@deepseek-ai/schemastery` | `vendor/schemastery` | `3.18.4` → `3.18.5-alpha.1` | 0 |
133
+
134
+ The only non-manifest, non-README change inside a peer package is a **new test
135
+ case** in `packages/api/gateway/tests/gateway.host.spec.ts`, which records a
136
+ behaviour fix: a Service already disposed is skipped during SRC resolution. No
137
+ shipped code changed, so `typertGateway.wireStream.open(endpoint, payload,
138
+ uplink, peer, signal)` keeps its argument order — the seam this plugin's
139
+ highest-risk integration depends on.
140
+
141
+ ### High-risk service surfaces
142
+
143
+ | Area | Finding | DeepPilot impact |
144
+ | --- | --- | --- |
145
+ | `api/session-controller` (`src/index.ts`, `src/list.ts`) | Adds one optional config key `listWorkSliceMs` (natural, min 1, **default 16**) and threads it into `new ApiSessionList(ctx, resolved.listWorkSliceMs)` so large listings yield between rows. No `@Remote` method signature changed. | None. The hand-written `SessionControllerLike` mirror still matches; the plugin never constructs the controller. |
146
+ | `api/workspace-controller` | Zero changed `src/` files. | None. |
147
+ | `schedule/schedule` | `src/tools.ts` and `src/invariant.ts` **deleted**; `ScheduleService.inject` drops `'tools'`; `src/types.ts` gains `SubagentSessionError`. | See the two rows below. |
148
+ | `boot/app-boot` | `createRuntimeResolution` now returns a `ProfileRuntimeResolution` **class instance** instead of a frozen plain object, and a new `RETIRED_BUNDLES` set exists. | None. `app-boot` is not in this plugin's peer set. |
149
+
150
+ ### The three announced breaking changes, checked against this plugin
151
+
152
+ Each was traced to its implementation in the DSH tree rather than accepted from
153
+ the release note.
154
+
155
+ | Breaking change | Where it actually lands | DeepPilot impact |
156
+ | --- | --- | --- |
157
+ | **Runtime invariant plugins and every `./invariant` export removed.** | `@deepseek-ai/dsh-invariants`, `InvariantRegistry`, `InvariantInstaller` and all `<package>/invariant` subpaths stop being published; `sdk-minimal` drops five rows. Official guide: `docs/upgrade-guide/v0.2.0-rc.2/remove-runtime-invariants/`. | **None.** The plugin source contains zero `invariant` references. In `package-lock.json` the package appears only as a transitive dependency of `dsh-credentials`, `dsh-scope`, `dsh-settings` and `dsh-system-prompt` — packages this plugin does not import or configure. `cordis.patch.yml` declares no invariant rows, so no `patch: entry ... not found` warning can occur. |
158
+ | **Subpath plugins no longer read their own `package.json`; text and icon must come from subpath exports.** | `boot/app-boot/src/package-meta.ts`: `manifestPath` is now `packageName === specifier ? optionalResourcePath(...) : undefined`, so only a package-root specifier reads a manifest; a subpath instead takes its icon from an exported `<specifier>/icon`. A new `assertPackageOwned` keeps an exported icon inside its owning package. Official guide: `docs/upgrade-guide/v0.2.0-rc.2/subpath-plugin-display-manifest/`, which states the affected group is "authors who export a subpath `package.json`". | **None.** `package.json` exports `./package.json` (package root) but **not** `./client/package.json`, and the root manifest still supplies `name`, `description` and `icon.svg`. Verified against Node's real exports gate in this repo: `dsh-deeppilot/client/package.json`, `dsh-deeppilot/client/icon` and `dsh-deeppilot/client/locale/en.json` all fail with `ERR_PACKAGE_PATH_NOT_EXPORTED` **today**, so the old code could never have resolved them either. Old and new resolution therefore produce the same result. |
159
+ | **Composer statistics split into `activity` and `usage` entries; plugins overriding the old `stats` row must change their registered ID.** | The `stats` composer row was reworked (the `composer-session-stats-pills` design note is archived). | **None.** The plugin registers exactly one client extension — `slots.inject('settings.section', ...)` in `src/client/index.ts:478` — and never registers a composer row. The `row.stats` at `src/host-bridge.ts:663` is this plugin's own wire structure, unrelated to the composer extension. |
160
+
161
+ ### Automation tasks moved into the Web composition
162
+
163
+ This is the one substantive product change, and it invalidates documentation
164
+ rather than code.
165
+
166
+ `boot/app-boot/src/profile.ts` adds:
167
+
168
+ ```ts
169
+ const RETIRED_BUNDLES: ReadonlySet<string> = new Set([
170
+ '@deepseek-ai/dsh-experimental-schedule-bundle',
171
+ ])
172
+ ```
173
+
174
+ and removes that bundle from `OPTIONAL_BUNDLES` (replaced by
175
+ `@deepseek-ai/dsh-experimental-inspector-profile`). `loadProfileDirectory`
176
+ rewrites the profile's `package.json` to drop the retired entry; stored tasks and
177
+ delivery records survive on disk. The official guide
178
+ (`docs/upgrade-guide/v0.2.0-rc.2/schedule-bundle-retired/`) states that
179
+ `@deepseek-ai/dsh-web-app` now mounts `schedule` and `ui-schedule` in **every**
180
+ Web profile.
181
+
182
+ The plugin needs no code change. It resolves the service lazily through
183
+ `ctx.get('schedule')` (the fix recorded in the 2026-09-29 entry), never lists
184
+ `schedule` in `inject`, and already reports `E_UNSUPPORTED` when the service is
185
+ absent. On a `0.2.1-alpha.1` Web profile the service is simply always present,
186
+ so `welcome.capabilities.schedules` becomes `true` by default instead of by
187
+ opt-in.
188
+
189
+ What is now wrong is the instruction the plugin gives users. `PROTOCOL.md`
190
+ (line 899), `COMPATIBILITY.md` (lines 39–47), `docs/RELEASE_NOTES-0.9.0.md`, and
191
+ `docs/DEEPPILOT_FEATURE_PLAN.md` all tell the user to enable **Automation tasks**
192
+ in the plugin manager, and the iOS copy repeats it. On this release that entry is
193
+ retired and auto-cleaned, so the instruction sends users after a bundle that no
194
+ longer exists.
195
+
196
+ The upgrade guide's migration step 2 — keep `schedule`/`ui-schedule` overrides in
197
+ a patch layer and delete a top-level `time-context` override — **does not apply
198
+ here**: `cordis.patch.yml` is 20 lines long and contains only the three
199
+ directory-picker rows, with no `schedule`, `ui-schedule` or `time-context`
200
+ entries.
201
+
202
+ ### New Schedule refusal: `subagent_session`
203
+
204
+ `ScheduleService` now refuses `create` and `update` when the target Session has
205
+ a delegation depth above zero, returning a new stable `ScheduleInputError`
206
+ code `subagent_session` ("This Session belongs to subagent routing, which never
207
+ receives reminder delivery"). `delete` deliberately still works so tasks stored
208
+ before the rule existed stay removable. The refusal is also visible to subagents
209
+ because the bridge reaches this code through the same `@Remote` methods.
210
+
211
+ `src/wire-errors.ts` now maps twelve Schedule codes, adding `subagent_session` →
212
+ `E_PROTOCOL` alongside `schedule_not_found`, `invalid_selector`, `not_future`,
213
+ `frequency_too_high`, `schedule_ended` and the rest. It was chosen over
214
+ `E_UNSUPPORTED` because the capability exists on the host — it is this request's
215
+ target that can never be satisfied, so a phone retry is pointless — which puts it
216
+ in the same class as the other input-shaped Schedule refusals. Without the
217
+ mapping `wireErrorOf` falls through to `WIRE_ERROR_FALLBACK` (`E_INTERNAL`), which
218
+ would tell the client the failure was worth retrying.
219
+
220
+ ### Cross-platform trap found while shipping 0.9.2
221
+
222
+ CI's `plugin` job hung on `npm test` four times while shipping 0.9.2. Worth
223
+ recording because macOS could never reproduce it and the fix is one line each.
224
+
225
+ `tests/journal-parity.test.ts` used `join('/proc/definitely/not/writable', …)`
226
+ as its "unwritable path" probe, in two places. `/proc` is a Linux-only pseudo
227
+ filesystem: on macOS the path simply does not exist, so the branch had only ever
228
+ been exercised on macOS and had never run on Linux at all. On Linux, writing
229
+ under `/proc` does not return an error — and because `dispatch-journal`'s
230
+ `save()` is entirely synchronous `fs` calls (`mkdirSync`/`openSync`/
231
+ `writeFileSync`/`fsyncSync`/`renameSync`), a single write blocks the whole event
232
+ loop. Even `setTimeout` stops firing, and node's `--test-timeout` can only report
233
+ a file-level timeout. Both sites now build the unwritable target inside the
234
+ scratch directory (a file-with-a-child shape that yields `ENOTDIR` identically on
235
+ every platform); recorded values are unchanged because all three candidate paths
236
+ returned the same status on macOS.
237
+
238
+ Two lessons for future audits: the workflow sets no `timeout-minutes`, so a hang
239
+ costs the full 6-hour default before failing — cancel and re-run rather than
240
+ waiting; and reproduce Linux-only behaviour in a container instead of inferring
241
+ it. `docker run --rm --cpus=2 -v $PWD:/app -w /app node:22` matches the runner
242
+ closely enough (2 cores, and the same `v22.23.x` that `node-version: 22` floats
243
+ to).
244
+
245
+ ### Re-audit procedure used
246
+
247
+ Same blobless-clone method as the rc.2 and rc.1 entries, with two refinements:
248
+ unshallow before measuring (a `--depth=1` clone silently under-reports the diff,
249
+ returning 4190 vs 4760 paths depending on history), and resolve peer package
250
+ names through a sparse `package.json` checkout instead of guessing directory
251
+ names — the monorepo maps `@deepseek-ai/dsh-api-gateway` to
252
+ `packages/api/gateway`, `@deepseek-ai/dsh` to `apps/cli`, and the two vendored
253
+ packages to `vendor/`.
254
+
38
255
  ## 2026-09-29 — audit of `dsh-v0.2.0-rc.2`
39
256
 
40
257
  ### Scope and method