@twinsearth/w2m-dsh-plugin 0.37.0 → 0.39.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 +99 -0
- package/docs/1.0.0-ACCEPTANCE.md +12 -4
- package/package.json +5 -4
- package/src/plugin/tools.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,105 @@ 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.39.0] — 2026-10-15
|
|
8
|
+
|
|
9
|
+
**The orphan gate: a module nothing reaches now fails the pre-flight unless a reason is written down.**
|
|
10
|
+
|
|
11
|
+
### What checking the remaining loops found — and it corrects a claim I made
|
|
12
|
+
|
|
13
|
+
0.36.0's classifier reported 86 closed loops and **could not say which were defects**, so it printed and
|
|
14
|
+
exited 0. This sorts them, and the result is uncomfortable and precise:
|
|
15
|
+
|
|
16
|
+
**Eight orphan modules, 72 exports, every one of them written in this span** — and **two were described as
|
|
17
|
+
delivered** while nothing ran them.
|
|
18
|
+
|
|
19
|
+
`approval-gate.mjs` **is** wired: `tools.mjs` imports it, constructs it, and calls `mayRaise` on the raise path.
|
|
20
|
+
**`field-authority.mjs` is not.** Reading the tree rather than my own changelog:
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
grep 'field-authority' src/ → comments and documentation only. Nothing imports it.
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
**0.29.0 said "the connection now exists". It exists inside that module and nowhere else.** That is now
|
|
27
|
+
recorded as a correction in `scripts/accepted-orphans.mjs`, in the entry that keeps it on the list.
|
|
28
|
+
|
|
29
|
+
### A dead branch, found by the test that could not be written
|
|
30
|
+
|
|
31
|
+
I added **second-order reachability** so that a module reached *through* another could be called a library
|
|
32
|
+
rather than an orphan. The test for it failed, and the reason is arithmetic:
|
|
33
|
+
|
|
34
|
+
> a row is `closed-loop` **only when no source file imports anything from it at all** — which is exactly what
|
|
35
|
+
> the `sibling-imported` class already excludes. **So there is never a first-order importer for a second-order
|
|
36
|
+
> walk to start from**, and the library case **cannot arise**.
|
|
37
|
+
|
|
38
|
+
Measured: **72 orphan, 0 library, 14 cli** — and **the zero was a tautology, not a finding.** The library
|
|
39
|
+
bucket is removed rather than printed as a permanent zero, and `LOOP_KIND.LIBRARY_UNREACHABLE` records *why*
|
|
40
|
+
so the next reader does not re-derive the idea. **Being a library is a claim about intent, and the import
|
|
41
|
+
graph cannot carry it — so the claim is made where it can be checked.**
|
|
42
|
+
|
|
43
|
+
### `scripts/accepted-orphans.mjs`, and why a list rather than a rule
|
|
44
|
+
|
|
45
|
+
Each accepted orphan names a **reason**, and **what would remove it**. `library` is a design choice;
|
|
46
|
+
`interface-unrouted` **is the defect**, kept only because removing it needs a decision about *where* it should
|
|
47
|
+
be reached from.
|
|
48
|
+
|
|
49
|
+
The gate is `checkOrphans` in the pre-flight: **a closed loop is red unless its file is on that list.** The
|
|
50
|
+
eight known ones are decisions somebody made; **a ninth fails the run and forces the same conversation.**
|
|
51
|
+
A stale entry — one that names a file no longer an orphan — also fails, so the list cannot quietly claim a
|
|
52
|
+
problem that is gone.
|
|
53
|
+
|
|
54
|
+
Four of the eight are marked `interface-unrouted` and said so plainly: `health` (the sensor the user asked for
|
|
55
|
+
by name), `log-bounds` (the answer to the 40× log growth, shipped in 0.12.0 and called by nothing), `storage`,
|
|
56
|
+
and `field-authority`.
|
|
57
|
+
|
|
58
|
+
### My own error, the same one as two rounds ago
|
|
59
|
+
|
|
60
|
+
`await` in a **non-async callback**, caught by `node --check` — **the second time in this span.** The fix is
|
|
61
|
+
the same both times: import it up front rather than reaching for it where it is not allowed.
|
|
62
|
+
|
|
63
|
+
**13 new tests, 0 failures.**
|
|
64
|
+
|
|
65
|
+
## [0.38.0] — 2026-10-15
|
|
66
|
+
|
|
67
|
+
**A seven-phase council run on MacMini — real-machine evidence for the tool that had never touched one.**
|
|
68
|
+
|
|
69
|
+
0.37.0's `w2m_council` was the only substantial addition in this span that had **never run anywhere but this
|
|
70
|
+
laptop.** It now has a measurement, and the exit code came from the machine:
|
|
71
|
+
|
|
72
|
+
```
|
|
73
|
+
OK phases=7 outcome=ship dissent=1 reproduced=true exit 0
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Driven through `node -e` on MacMini against its own checkout at 0.37.0: the council was convened, roles
|
|
77
|
+
assigned, two arguments recorded, two weighted votes cast, the outcome fixed, the decision sealed, and the
|
|
78
|
+
sealed decision **read back after the council stopped being advanceable** — with its dissent, its reason, and a
|
|
79
|
+
`recount` that reproduced the outcome from the stored ballots. **Every one of those was asserted before the
|
|
80
|
+
process was allowed to exit `0`**, so this is not a "did it load" smoke test.
|
|
81
|
+
|
|
82
|
+
### The same run answered a question that had only been a hypothesis for four rounds
|
|
83
|
+
|
|
84
|
+
**v4.10.0's council works on MacMini because it reaches for nothing that machine lacks.** `council.mjs` imports
|
|
85
|
+
`node:crypto` and `./authority.mjs`, and neither needs `node_modules`. The eight suites that failed there in
|
|
86
|
+
0.32.0 therefore failed on **what their fixtures reach for**, not on the modules under test — **a measurement
|
|
87
|
+
now, where four earlier releases recorded a guess as a guess.**
|
|
88
|
+
|
|
89
|
+
It also sharpens the shape of that failure: a suite whose *subject* has no dependencies still fails if the
|
|
90
|
+
*suite* imports one, and **from an exit code alone the two are indistinguishable.**
|
|
91
|
+
|
|
92
|
+
### The sixth time I exceeded the ceiling
|
|
93
|
+
|
|
94
|
+
The update dispatch — download a release tarball and extract it — **expired**. Measured again, and the number
|
|
95
|
+
has not moved: the agent's lease survives roughly **50 seconds** (`heartbeatIntervalMs 10s × missedHeartbeats 2
|
|
96
|
+
+ leaseGraceMs 30s`), and an expired lease carries **no exit code at all**, so the work was lost rather than
|
|
97
|
+
reported as failed.
|
|
98
|
+
|
|
99
|
+
**What matters is what happened next:** rather than retrying the download, a **three-line probe** established
|
|
100
|
+
that the extraction had in fact completed — **the partial run had succeeded and only the report was lost.** A
|
|
101
|
+
retry would have spent another dispatch redoing finished work, and could have raced the `tar` it had left
|
|
102
|
+
half-written.
|
|
103
|
+
|
|
104
|
+
**No new tests.** What changed is a measurement, and a hypothesis that stopped being one.
|
|
105
|
+
|
|
7
106
|
## [0.37.0] — 2026-10-15
|
|
8
107
|
|
|
9
108
|
**`council.mjs` is wired. v4.10.0's committee governance is reachable, and its dissent arrives with its decision.**
|
package/docs/1.0.0-ACCEPTANCE.md
CHANGED
|
@@ -68,16 +68,24 @@ declared its own `export const AUTHORITY_MAX = 100` instead of importing the bou
|
|
|
68
68
|
**Two copies of a limit that nothing can keep in step, failing silently** — raise the real maximum and this
|
|
69
69
|
module keeps refusing `101` while naming the wrong number as authoritative. It now imports it.
|
|
70
70
|
|
|
71
|
-
### `v4.10.0`'s council
|
|
71
|
+
### `v4.10.0`'s council was BUILT AND NOT ROUTED — **fixed in 0.37.0**
|
|
72
72
|
|
|
73
73
|
`reachability-classify` reported `src/agent/council.mjs` as a closed loop, and reading it to check that
|
|
74
74
|
confirmed the finding: **275 lines implementing committee governance, imported by nothing but its own suite.**
|
|
75
75
|
`v4.10.0` is marked *shipped in 0.11.0* in `ROADMAP.md`, and **0.30.0 verified its three falsifying tests are
|
|
76
76
|
asserted by name** — which they are. **What was never checked is whether anything routes a question to it.**
|
|
77
77
|
|
|
78
|
-
**This
|
|
79
|
-
reachability work was built to find.
|
|
80
|
-
|
|
78
|
+
**This was the same defect as `field-authority` and `approval-gate`, in a third module** — the one the
|
|
79
|
+
reachability work was built to find.
|
|
80
|
+
|
|
81
|
+
**`w2m_council` now routes it.** The state lives in `createCouncilSessions` because a council walks **seven
|
|
82
|
+
phases across many calls** and one held inside a single invocation **could never finish**. Every read of a
|
|
83
|
+
decision returns the **dissent with its reasons** and a **`recount`**, so v4.10.0's third falsifying test —
|
|
84
|
+
*"a decision with recorded dissent is retrievable with the dissent"* — holds **after the council that produced
|
|
85
|
+
it is gone**, which is a property of the session rather than of the decision. Both are tested.
|
|
86
|
+
|
|
87
|
+
**A tie is still refused, not broken**, and the tool does not paper over it: a split council is the one case
|
|
88
|
+
where the council exists to escalate to a person.
|
|
81
89
|
|
|
82
90
|
---
|
|
83
91
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.39.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",
|
|
@@ -113,13 +113,13 @@
|
|
|
113
113
|
}
|
|
114
114
|
},
|
|
115
115
|
"scripts": {
|
|
116
|
-
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.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/layer-model.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/chatops-fleet-join.test.mjs",
|
|
116
|
+
"test": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.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/layer-model.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/chatops-fleet-join.test.mjs",
|
|
117
117
|
"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",
|
|
118
118
|
"test:relay": "node --test --test-force-exit test/relay.test.mjs",
|
|
119
119
|
"test:agent": "node --test --test-force-exit test/agent.test.mjs test/memory.test.mjs",
|
|
120
120
|
"test:tools": "node --test --test-force-exit test/tools.test.mjs",
|
|
121
121
|
"test:crossnetwork": "node --test --test-force-exit test/crossnetwork.test.mjs",
|
|
122
|
-
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.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/layer-model.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/chatops-fleet-join.test.mjs",
|
|
122
|
+
"test:all": "node --test --test-force-exit test/relay.test.mjs test/broadcast.test.mjs test/agent.test.mjs test/authority.test.mjs test/blocks.test.mjs test/approval-index.test.mjs test/fleet-sync.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/layer-model.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/chatops-fleet-join.test.mjs",
|
|
123
123
|
"pack": "node scripts/pack.mjs",
|
|
124
124
|
"verify:join": "node scripts/verify-join.mjs",
|
|
125
125
|
"lint": "eslint .",
|
|
@@ -153,7 +153,8 @@
|
|
|
153
153
|
"test:reachability": "node --test --test-force-exit test/reachability-check.test.mjs",
|
|
154
154
|
"reachability": "node scripts/reachability-check.mjs",
|
|
155
155
|
"reachability:classify": "node scripts/reachability-classify.mjs",
|
|
156
|
-
"test:council-session": "node --test --test-force-exit test/council-session.test.mjs"
|
|
156
|
+
"test:council-session": "node --test --test-force-exit test/council-session.test.mjs",
|
|
157
|
+
"orphans": "node --test --test-force-exit test/accepted-orphans.test.mjs"
|
|
157
158
|
},
|
|
158
159
|
"keywords": [
|
|
159
160
|
"dsh-bundle",
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -202,7 +202,7 @@ const MAX_STAGES = 16;
|
|
|
202
202
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
203
203
|
* overrides it at runtime for tests and packagers.
|
|
204
204
|
*/
|
|
205
|
-
const PLUGIN_VERSION = '0.
|
|
205
|
+
const PLUGIN_VERSION = '0.39.0';
|
|
206
206
|
|
|
207
207
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
208
208
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|