@twinsearth/w2m-dsh-plugin 0.15.0 → 0.16.0

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
@@ -4,6 +4,52 @@ All notable changes to this project are documented here. The format follows
4
4
  [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project
5
5
  adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [0.16.0] — 2026-10-15
8
+
9
+ **A non-zero exit code is not a fleet failure, and this session conflated them repeatedly.**
10
+
11
+ Twelve real task reports were fetched one request at a time — the only correct input, since `w2m_history`
12
+ records current lease state rather than outcomes — and the measured result was **12 acting leases, 12 `done`,
13
+ 0 expired, 0 refused**. Yet several runs in the same session produced no result at all. Both facts are true.
14
+
15
+ They are different failures, and the difference decides where a reader looks:
16
+
17
+ | Observation | What it means | Where the fault is |
18
+ |---|---|---|
19
+ | `exit_code: 70`, `lease_state: done` | **The command ran and reported 70.** The fleet worked. | the command |
20
+ | `exit_code: null`, `lease_state: expired` | **No result was ever produced.** | the machine, the lease, or the network |
21
+
22
+ `classifyLease()` and `isFleetFailure()` now encode that distinction, and **`exit_code` is the decisive field,
23
+ not the lease state** — a lease can be `done` while its command returned non-zero, which is a *successful
24
+ execution of a failing command*. `isFleetFailure` returns true only for the no-result case; a refusal is the
25
+ request being wrong, and an observer was never asked to act.
26
+
27
+ A rate that merged the two would report a healthy fleet as broken, or a broken one as healthy, depending on
28
+ which it happened to count.
29
+
30
+ ### The measured fleet, this round
31
+
32
+ | Measure | Value | Note |
33
+ |---|---|---|
34
+ | acting leases | 12 of 12 | a bounded sample, fetched per task |
35
+ | expiry rate | **0.0 %** | 0 expired in the sample |
36
+ | refusal rate | **0.0 %** | 0 refused |
37
+ | direct share | **0.0 %** | **every task went by relay** |
38
+ | P2P delivery rate | **0.0 %** | no direct channel was ever established |
39
+ | fleet size | **3 usable of 5 paired** | two `win-desktop` silent ≈ 17.2 h |
40
+
41
+ **The 0 % direct share is the finding worth acting on**: not one task in the sample used a direct path, so the
42
+ entire fleet has been running on the relay at RTT **354 ms** (macmini) and **336 ms** (ToFuture) where
43
+ jp-shared answers in **20 ms**.
44
+
45
+ ### Still not fixed
46
+
47
+ The two relay endpoints still disagree about whether the silent machines are online — `reconcile()` detects it
48
+ and says which to trust, but the disagreement itself needs a change on the relay, and this session has no shell
49
+ on that host.
50
+
51
+ **24 tests, 0 failures.**
52
+
7
53
  ## [0.15.0] — 2026-10-15
8
54
 
9
55
  **The fleet is three machines, not five — and two relay endpoints disagree about it.**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@twinsearth/w2m-dsh-plugin",
3
- "version": "0.15.0",
3
+ "version": "0.16.0",
4
4
  "description": "DSH: Windows2MacOS — drive the same project on online Windows and macOS machines from one DeepSeek account, across networks and regions. P2P hole punching is the default path (relay + shared server as rendezvous, ledger and fallback), with a bundled STUN responder, Tailscale/public-VPS/tunnel shapes, Rabbit relay + per-machine Localside + eight DSH tools (replicate / split), nine aggregate verdicts and signed requests.",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",
@@ -48,6 +48,69 @@ export const FAILURE_STATES = Object.freeze(['expired', 'timeout']);
48
48
  /** Outcomes that are not the fleet's fault, so they are counted separately. */
49
49
  export const REQUEST_FAULT_STATES = Object.freeze(['refused']);
50
50
 
51
+ /**
52
+ * How a lease ended, told apart properly.
53
+ *
54
+ * ## The conflation this exists to prevent
55
+ *
56
+ * This session repeatedly read `exit_code: 70` as a failure and `lease_state: expired` as the same kind of
57
+ * failure. **They are not the same kind of thing at all**, and the difference decides where a reader looks:
58
+ *
59
+ * * `exit_code: 70` with `lease_state: done` means **the command ran and reported 70**. The fleet worked.
60
+ * The number is the command's answer, and the machine is fine.
61
+ * * `exit_code: null` with `lease_state: expired` means **no result was ever produced**. The command may not
62
+ * have started. Nothing is known about what it did, and the machine — or the lease, or the network — is
63
+ * where the fault is.
64
+ *
65
+ * Measured: twelve consecutive real reports showed **12 acting leases, 12 `done`, 0 expired** — while several
66
+ * runs in the same session had produced no result at all. Both facts are true; they are different failures.
67
+ * A rate that merged them would report a healthy fleet as broken, or a broken one as healthy, depending on
68
+ * which it happened to count.
69
+ */
70
+ export const LEASE_OUTCOME = Object.freeze({
71
+ RAN: 'ran', // a result was produced, whatever it said
72
+ NO_RESULT: 'no_result', // nothing came back; the command's behaviour is unknown
73
+ REFUSED: 'refused', // the allow-list rejected it before it could run
74
+ OBSERVED_ONLY: 'observed', // the machine was told the outcome without being asked to act
75
+ UNKNOWN: 'unknown',
76
+ });
77
+
78
+ /**
79
+ * Classify one machine entry from a task report.
80
+ *
81
+ * `exit_code` is the decisive field, **not** the lease state: a lease can be `done` while its command
82
+ * returned non-zero, and that is a successful execution of a failing command.
83
+ */
84
+ export function classifyLease(entry) {
85
+ if (entry === null || typeof entry !== 'object') return { outcome: LEASE_OUTCOME.UNKNOWN, ran: false, exit_code: null, detail: 'no machine entry' };
86
+ const state = String(entry.lease_state ?? entry.outcome ?? '');
87
+ const code = entry.exit_code;
88
+ if (state === 'observing') return { outcome: LEASE_OUTCOME.OBSERVED_ONLY, ran: false, exit_code: null, detail: 'told the outcome, not asked to act' };
89
+ if (state === 'refused') return { outcome: LEASE_OUTCOME.REFUSED, ran: false, exit_code: null, detail: entry.refusal_reason ?? 'refused' };
90
+ if (state === 'done') {
91
+ return {
92
+ outcome: LEASE_OUTCOME.RAN,
93
+ ran: true,
94
+ exit_code: Number.isFinite(code) ? code : null,
95
+ detail: Number.isFinite(code) && code !== 0
96
+ ? `ran and reported ${code} -- the command's answer, not a fleet failure`
97
+ : 'ran and reported success',
98
+ };
99
+ }
100
+ if (state === 'expired' || state === 'timeout') {
101
+ return { outcome: LEASE_OUTCOME.NO_RESULT, ran: false, exit_code: null, detail: 'no result was produced; what the command did is unknown' };
102
+ }
103
+ return { outcome: LEASE_OUTCOME.UNKNOWN, ran: false, exit_code: null, detail: `unrecognised lease state ${JSON.stringify(state)}` };
104
+ }
105
+
106
+ /**
107
+ * Whether a non-zero exit code is a fleet failure. It is not, and this function exists so a caller does not
108
+ * have to decide that for itself each time.
109
+ */
110
+ export function isFleetFailure(entry) {
111
+ return classifyLease(entry).outcome === LEASE_OUTCOME.NO_RESULT;
112
+ }
113
+
51
114
  /**
52
115
  * Summarise a set of task reports.
53
116
  *
@@ -185,7 +185,7 @@ const MAX_STAGES = 16;
185
185
  * `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
186
186
  * overrides it at runtime for tests and packagers.
187
187
  */
188
- const PLUGIN_VERSION = '0.15.0';
188
+ const PLUGIN_VERSION = '0.16.0';
189
189
 
190
190
  /** How long any single HTTP call may take before it is aborted, in milliseconds. */
191
191
  const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;