@twinsearth/w2m-dsh-plugin 1.0.13 → 1.0.15

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.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,104 @@
2
2
 
3
3
  All notable changes to this project are documented here.
4
4
 
5
+ ## [1.0.15] — 2026-10-17
6
+
7
+ **Every 1.0.x GitHub release was missing its `SHA256SUMS` asset, so updating from GitHub could not be verified and
8
+ would be refused. That is fixed, along with the two tests that were failing on Linux CI.**
9
+
10
+ ### The product defect: un-updatable releases
11
+
12
+ `src/plugin/update-source.mjs` refuses to offer an update without a checksum asset:
13
+
14
+ > `no SHA256SUMS asset for ${tag}; cannot verify a download without it`
15
+
16
+ The 0.x releases carry **two** assets (tarball + sums). **When the 1.0 line was cut, the release script uploaded only the
17
+ tarball** -- so every 1.0.x release looked complete and was, in fact, **un-updatable from GitHub**. Nothing local could
18
+ have caught it: the tarball was present and correct, and only a job that calls the real API noticed.
19
+
20
+ Fixed in three places:
21
+
22
+ * `scripts/github-release.mjs` now derives the sums from the same bytes it uploads and attaches `SHA256SUMS` in the
23
+ same run, **and reads back the asset list** so a missing sums file is a release failure rather than a warning;
24
+ * the asset has been backfilled on **all fourteen** 1.0.x releases (v1.0.1 … v1.0.14), each checksum computed from the
25
+ bytes GitHub actually serves;
26
+ * the live-API test in `test/update-source.test.mjs` now passes -- it was the only thing that ever reported this.
27
+
28
+ ### Two tests that failed only on Linux CI
29
+
30
+ Both were invisible on Windows, and both were **the test's** fault, not the code's:
31
+
32
+ **`test/vision.test.mjs`** created its settings fixture with the default umask, which is `0644` on Linux. The loader
33
+ correctly refuses a file that holds a key and is group-readable, so the test got *"mode 644"* instead of the message it
34
+ asserted. **The fixture should be 0600; the guard was right.**
35
+
36
+ **`test/chatops-bridge.test.mjs`** faked its timer with a real `setTimeout`. The broker calls `record.timer.unref()`,
37
+ so during the await the only pending handle is an **unref'd** timeout -- which does not keep the event loop alive. On
38
+ Linux the loop drained before it fired and node reported
39
+ `cancelledByParent: Promise resolution is still pending but the event loop has already resolved`. **It passed on Windows
40
+ by accident of scheduling.** The timer is now deterministic: the callback is captured and fired explicitly.
41
+
42
+ ### Release titles are version numbers
43
+
44
+ The repository home page sidebar renders the latest release's **name**, and the name was the commit subject:
45
+
46
+ > `test(merge): verify merging while a third machine publishes -- never tears, …`
47
+
48
+ -- where a reader looking for "which version is current?" expects `v1.0.14`. The title is now the tag; **the commit
49
+ subject moved to the first line of the body**, so nothing is lost and the one slot that names the release names the
50
+ version. All fourteen 1.0.x releases were renamed to match.
51
+
52
+ ### Verified
53
+
54
+ Full suite **2380 tests in 93 files, 2366 pass, 0 fail, 14 skip**; pre-flight **GREEN, 15 of 15 checks**.
55
+ `test/update-source.test.mjs` (which makes a real GitHub API call) passes: **50 tests, 49 pass, 0 fail**.
56
+
57
+ ## [1.0.14] — 2026-10-17
58
+
59
+ **Merging while a third machine publishes is verified: it never tears, never writes, and names its failures.**
60
+
61
+ ### The gap this closes, stated precisely
62
+
63
+ v1.0.12 verified the memory actions end to end **one machine at a time**. v1.0.13 verified concurrent *publishing*.
64
+ **Neither covered a merge racing a publish**, and the merge has a two-step read that a publish can break:
65
+
66
+ 1. `GET /v1/fleet/blobs/latest` — learn the hash;
67
+ 2. `GET /v1/fleet/blobs/<hash>` — fetch the bytes, re-hash, merge.
68
+
69
+ Between those steps the pointer can advance (harmless: the merge still reads the blob it was told about) or the blob
70
+ can be **evicted** (fatal if unhandled: a 404 where the code expected bytes).
71
+
72
+ ### What "correct" means for a racing read
73
+
74
+ There is no single right answer for *which* document a racing merge sees -- that is the nature of a read that is not in
75
+ a transaction. What is required:
76
+
77
+ * it **never throws an error it cannot name**;
78
+ * it **never produces a torn merge** -- a result whose recorded decision disagrees with the text it produced;
79
+ * it **never writes the local file**, under any outcome;
80
+ * when the blob is gone mid-flight, it **says so by name**.
81
+
82
+ ### Verified
83
+
84
+ Two tests in `test/fleet-merge-race.test.mjs`:
85
+
86
+ * **twenty rounds of a merge fired together with a publish.** Every round resolved: a completed merge with a
87
+ consistent decision, or a **named** `W2M_*` refusal. No crash. No torn merge -- when the recorded winner is
88
+ `local` the text carries the local value, when it is `fleet` it carries a fleet value. **The local document was
89
+ re-read after every round and was untouched every time.** The test also asserts at least one merge *completed*, so it
90
+ cannot pass vacuously by refusing everything.
91
+ * **a pointer naming a blob that no longer exists** raises `W2M_NOT_FOUND`, not a crash.
92
+
93
+ **One honest limitation of the second test:** it *sets up* the state the race would produce (pointer names a removed
94
+ blob) rather than catching the removal in flight. **The code path is identical; the timing is not.** Recorded because
95
+ "mid-flight" without that caveat would overstate the evidence.
96
+
97
+ ### Still not verified, and now the list is short
98
+
99
+ **Two relay processes sharing one state directory.** The design is one relay per fleet; supporting the other would need
100
+ real file locking, and nothing here provides it. **"Concurrency is tested" must not be read as "any topology is safe"**
101
+ -- that sentence was written into v1.0.13's notes and it still applies.
102
+
5
103
  ## [1.0.13] — 2026-10-17
6
104
 
7
105
  **Concurrent publishing is verified safe on one relay, and the reason it is safe is stated so a future change can
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/w2m-dsh-plugin",
3
- "version": "1.0.13",
3
+ "version": "1.0.15",
4
4
  "description": "Run one project across your own Windows and macOS machines from a single DeepSeek account, through 11 w2m_* tools. Four coordination modes (replicate, split, broadcast, pipeline) and six aggregate verdicts (consistent, divergent, divergent-platform, failed, partial, unverifiable). P2P hole punching by default, with a bundled relay, STUN responder and ledger fallback, so the fleet needs no third-party service. Joining needs a pairing code plus autoStartAgent: true; installing alone does not join.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -117,13 +117,13 @@
117
117
  }
118
118
  },
119
119
  "scripts": {
120
- "test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/fleet-concurrency.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
120
+ "test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/fleet-concurrency.test.mjs test/fleet-merge-race.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-crypto.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
121
121
  "test:e2e": "node --test --test-force-exit test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/p2p-agent.test.mjs",
122
122
  "test:relay": "node --test --test-force-exit test/relay.test.mjs",
123
123
  "test:agent": "node --test --test-force-exit test/agent.test.mjs test/memory.test.mjs",
124
124
  "test:tools": "node --test --test-force-exit test/tools.test.mjs",
125
125
  "test:crossnetwork": "node --test --test-force-exit test/crossnetwork.test.mjs",
126
- "test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/fleet-concurrency.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
126
+ "test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/plan-sec-cmd.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.test.mjs test/fleet-merge.test.mjs test/fleet-memory-e2e.test.mjs test/fleet-concurrency.test.mjs test/fleet-merge-race.test.mjs test/health.test.mjs test/storage.test.mjs test/exit-channel.test.mjs test/council.test.mjs test/council-session.test.mjs test/log-bounds.test.mjs test/test-report.test.mjs test/fleet-scale.test.mjs test/fleet-state.test.mjs test/crypto-blake2s.test.mjs test/installed-version.test.mjs test/permission.test.mjs test/machine-test-packet.test.mjs test/field-authority.test.mjs test/approval-gate.test.mjs test/authority-choice.test.mjs test/reachability-check.test.mjs test/reachability-classify.test.mjs test/accepted-orphans.test.mjs test/acceptance-doc.test.mjs test/layer-model.test.mjs test/cwd-containment.test.mjs test/cwd-outside-project.test.mjs test/memory.test.mjs test/tools.test.mjs test/claims.test.mjs test/fleet-target.test.mjs test/client-bundle.test.mjs test/schedule.test.mjs test/auto-update.test.mjs test/update-source.test.mjs test/update-install.test.mjs test/update-wiring.test.mjs test/signing.test.mjs test/stress.test.mjs test/e2e.test.mjs test/crossnetwork.test.mjs test/signing-e2e.test.mjs test/outbound-only.test.mjs test/recovery.test.mjs test/pipeline-e2e.test.mjs test/shared-config.test.mjs test/metrics.test.mjs test/metrics-route.test.mjs test/tool-cards.test.mjs test/p2p-stun.test.mjs test/p2p-transport.test.mjs test/p2p-signaling.test.mjs test/p2p-node.test.mjs test/p2p-transport-fields.test.mjs test/p2p-plugin.test.mjs test/p2p-agent.test.mjs test/stun-server.test.mjs test/loader-entry.test.mjs test/mdns-wire.test.mjs test/mdns-discover.test.mjs test/p2p-crypto.test.mjs test/chatops-approval.test.mjs test/chatops-policy.test.mjs test/chatops-file-safety.test.mjs test/chatops-outbound-queue.test.mjs test/chatops-commands.test.mjs test/chatops-bridge.test.mjs test/chatops-config-route.test.mjs test/chatops-apply.test.mjs test/chatops-ilink-contract.test.mjs test/chatops-fleet.test.mjs test/chatops-account.test.mjs test/chatops-auth.test.mjs test/chatops-fleet-scope.test.mjs test/chatops-handoff.test.mjs test/chatops-fleet-wiring.test.mjs test/chatops-fleet-live.test.mjs test/chatops-takeover.test.mjs test/chatops-device-signing.test.mjs test/chatops-relay-verify.test.mjs test/chatops-durability.test.mjs test/chatops-run-command.test.mjs test/secrets-guard.test.mjs test/chatops-ilink-fleet-bridge.test.mjs test/agent-plugins.test.mjs test/memory-layer.test.mjs test/mcp-server.test.mjs test/mcp-http.test.mjs test/mcp-http-live.test.mjs test/vision.test.mjs test/ilink-shape.test.mjs test/chatops-fleet-join.test.mjs",
127
127
  "pack": "node scripts/pack.mjs",
128
128
  "verify:join": "node scripts/verify-join.mjs",
129
129
  "lint": "eslint .",
@@ -140,6 +140,7 @@
140
140
  "test:fleet-merge": "node --test --test-force-exit test/fleet-merge.test.mjs",
141
141
  "test:fleet-memory-e2e": "node --test --test-force-exit test/fleet-memory-e2e.test.mjs",
142
142
  "test:fleet-concurrency": "node --test --test-force-exit test/fleet-concurrency.test.mjs",
143
+ "test:fleet-merge-race": "node --test --test-force-exit test/fleet-merge-race.test.mjs",
143
144
  "test:health": "node --test --test-force-exit test/health.test.mjs",
144
145
  "test:storage": "node --test --test-force-exit test/storage.test.mjs",
145
146
  "test:exit-channel": "node --test --test-force-exit test/exit-channel.test.mjs",
package/plugin.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
3
3
  "name": "twinsearth-w2m-dsh",
4
- "version": "1.0.13",
4
+ "version": "1.0.15",
5
5
  "description": "Run one project across your own Windows and macOS machines from a single DeepSeek account, through 11 w2m_* tools. Four coordination modes (replicate, split, broadcast, pipeline) and six aggregate verdicts (consistent, divergent, divergent-platform, failed, partial, unverifiable). P2P hole punching by default, with a bundled relay, STUN responder and ledger fallback, so the fleet needs no third-party service. Joining needs a pairing code plus autoStartAgent: true; installing alone does not join.",
6
6
  "license": "MIT",
7
7
  "keywords": [
@@ -211,7 +211,7 @@ const MAX_STAGES = 16;
211
211
  * `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
212
212
  * overrides it at runtime for tests and packagers.
213
213
  */
214
- const PLUGIN_VERSION = '1.0.13';
214
+ const PLUGIN_VERSION = '1.0.15';
215
215
 
216
216
  /** How long any single HTTP call may take before it is aborted, in milliseconds. */
217
217
  const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;