@twinsearth/w2m-dsh-plugin 0.35.0 → 0.36.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 +42 -0
- package/docs/1.0.0-ACCEPTANCE.md +31 -1
- package/package.json +5 -4
- package/src/agent/council.mjs +19 -2
- package/src/plugin/tools.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,48 @@ 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.36.0] — 2026-10-15
|
|
8
|
+
|
|
9
|
+
**The classification found a third closed loop — and it is `council.mjs`, which `ROADMAP.md` marks shipped.**
|
|
10
|
+
|
|
11
|
+
### What the classifier does that a regex cannot
|
|
12
|
+
|
|
13
|
+
468 findings against this repository, and the one real defect in them was invisible. Refining the pattern
|
|
14
|
+
cannot fix that: **the information is not in the name, it is in the shape of the import graph.**
|
|
15
|
+
|
|
16
|
+
The shape that identified the two known defects was — **one export, one importer, and that importer is the
|
|
17
|
+
test named after the module.** That is not a heuristic about naming; it is a statement about the graph: **a
|
|
18
|
+
module whose only importer is its own suite exists in a closed loop, and nothing in the program reaches it.**
|
|
19
|
+
The name is used only to decide whether the loop is *closed*.
|
|
20
|
+
|
|
21
|
+
Against this repository: **316 `sibling-imported`, 91 `closed-loop`, 61 `same-module`.**
|
|
22
|
+
|
|
23
|
+
**91 is not a defect count and the classifier says so**, in three tests that pin its own limits rather than
|
|
24
|
+
commenting on them: it cannot see a **dynamic import** (`await import('./x.mjs')` names no binding), and it
|
|
25
|
+
cannot see a module reached only because a **CLI entry point spawns it** — which is every file in `scripts/`,
|
|
26
|
+
and is why that number is large.
|
|
27
|
+
|
|
28
|
+
### `v4.10.0`'s council is BUILT, NOT ROUTED
|
|
29
|
+
|
|
30
|
+
`src/agent/council.mjs` is a closed loop: **275 lines implementing committee governance, imported by nothing
|
|
31
|
+
but its own suite.** `ROADMAP.md` marks v4.10.0 *shipped in 0.11.0*, and 0.30.0 verified its three falsifying
|
|
32
|
+
tests are asserted by name — **which they are.** What was never checked is whether anything routes a question
|
|
33
|
+
to it. **Same defect as `field-authority` and `approval-gate`, in a third module**, and the one the
|
|
34
|
+
reachability work existed to find. Recorded as **built, not routed**, and routing it needs a tool surface and
|
|
35
|
+
a session rather than a line of code.
|
|
36
|
+
|
|
37
|
+
### A duplicated limit, found by reading the file to check the first finding
|
|
38
|
+
|
|
39
|
+
`council.mjs` declared its own `export const AUTHORITY_MAX = 100` instead of importing the bound from
|
|
40
|
+
`authority.mjs`. **Two copies of a limit that nothing can keep in step, and the failure is silent**: raise the
|
|
41
|
+
real maximum and this module keeps refusing `101` while naming the wrong number as authoritative. It now
|
|
42
|
+
imports it, and `AUTHORITY_MAX` has exactly one literal definition in `src/`.
|
|
43
|
+
|
|
44
|
+
**Reading the file to check the wiring finding is how the constant surfaced** — the argument for investigating
|
|
45
|
+
a report rather than counting it.
|
|
46
|
+
|
|
47
|
+
**10 new tests, 0 failures.**
|
|
48
|
+
|
|
7
49
|
## [0.35.0] — 2026-10-15
|
|
8
50
|
|
|
9
51
|
**§1.5 measured at last: the reachability report, and the honest reason it is not a gate.**
|
package/docs/1.0.0-ACCEPTANCE.md
CHANGED
|
@@ -18,7 +18,7 @@ but has no caller, that is stated in its own column rather than hidden behind a
|
|
|
18
18
|
| 1.2 | Every dependency edge is declared, and every declared edge is used | `scripts/layer-check.mjs` | **yes** |
|
|
19
19
|
| 1.3 | Every suite on disk is named by a script | pre-flight `test wiring`, `claims` | **yes** — reported, not silently ignored |
|
|
20
20
|
| 1.4 | Every document's claim about the artifact matches the artifact | `test/claims.test.mjs` | **yes** — 48 claims, and it has caught real drift |
|
|
21
|
-
| 1.5 | No module is unreachable — every declared thing has a caller | `scripts/reachability-check.mjs` | **MEASURED, not enforced — see below** |
|
|
21
|
+
| 1.5 | No module is unreachable — every declared thing has a caller | `scripts/reachability-check.mjs`, `reachability-classify.mjs` | **MEASURED, not enforced — see below** |
|
|
22
22
|
|
|
23
23
|
`1.5` is the row that mattered most and the one that went unsatisfied longest. This span shipped three
|
|
24
24
|
mechanisms that were, for a round each, fully tested and completely uncalled: `field-authority.mjs`,
|
|
@@ -49,6 +49,36 @@ reliable for — including the false positive that broke the first version, `dee
|
|
|
49
49
|
**So `1.5` is measured, not closed.** A defect of this class is now *visible*; it is not *prevented*, and
|
|
50
50
|
nothing in the pre-flight fails when one appears.
|
|
51
51
|
|
|
52
|
+
### What the classification found, and what it reported about itself
|
|
53
|
+
|
|
54
|
+
`reachability-classify.mjs` sorts the findings by **the shape of the import graph** rather than by name. The
|
|
55
|
+
shape that identified the two known defects was: **one export, one importer, and that importer is the test
|
|
56
|
+
named after the module** — a closed loop, where nothing in the program reaches the code.
|
|
57
|
+
|
|
58
|
+
Against this repository: **468 findings, 316 `sibling-imported`, 91 `closed-loop`, 61 `same-module`.**
|
|
59
|
+
|
|
60
|
+
**The 91 is not a defect count, and the classifier says so in three pinned tests.** It cannot see a
|
|
61
|
+
**dynamic import** (`await import('./x.mjs')` names no binding) and it cannot see a module reached only because
|
|
62
|
+
a **CLI entry point spawns it** — which is every file in `scripts/`, and is why that number is large. Both
|
|
63
|
+
limits are asserted rather than commented, because a classifier whose limits are undocumented gets trusted
|
|
64
|
+
past them.
|
|
65
|
+
|
|
66
|
+
**Investigating one finding by hand found a real defect that the count had buried**: `src/agent/council.mjs`
|
|
67
|
+
declared its own `export const AUTHORITY_MAX = 100` instead of importing the bound from `authority.mjs`.
|
|
68
|
+
**Two copies of a limit that nothing can keep in step, failing silently** — raise the real maximum and this
|
|
69
|
+
module keeps refusing `101` while naming the wrong number as authoritative. It now imports it.
|
|
70
|
+
|
|
71
|
+
### `v4.10.0`'s council is built and not routed — found here, not claimed before
|
|
72
|
+
|
|
73
|
+
`reachability-classify` reported `src/agent/council.mjs` as a closed loop, and reading it to check that
|
|
74
|
+
confirmed the finding: **275 lines implementing committee governance, imported by nothing but its own suite.**
|
|
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
|
+
asserted by name** — which they are. **What was never checked is whether anything routes a question to it.**
|
|
77
|
+
|
|
78
|
+
**This is the same defect as `field-authority` and `approval-gate`, in a third module**, and it is the one the
|
|
79
|
+
reachability work was built to find. It is recorded here as **BUILT, NOT ROUTED** rather than described as
|
|
80
|
+
delivered, and routing it needs a tool surface and a session — not a line of code.
|
|
81
|
+
|
|
52
82
|
---
|
|
53
83
|
|
|
54
84
|
## 2. 分层级 — layers, with a direction
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.36.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/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/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/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",
|
|
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/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/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/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",
|
|
123
123
|
"pack": "node scripts/pack.mjs",
|
|
124
124
|
"verify:join": "node scripts/verify-join.mjs",
|
|
125
125
|
"lint": "eslint .",
|
|
@@ -151,7 +151,8 @@
|
|
|
151
151
|
"test:approval-gate": "node --test --test-force-exit test/approval-gate.test.mjs",
|
|
152
152
|
"test:authority-choice": "node --test --test-force-exit test/authority-choice.test.mjs",
|
|
153
153
|
"test:reachability": "node --test --test-force-exit test/reachability-check.test.mjs",
|
|
154
|
-
"reachability": "node scripts/reachability-check.mjs"
|
|
154
|
+
"reachability": "node scripts/reachability-check.mjs",
|
|
155
|
+
"reachability:classify": "node scripts/reachability-classify.mjs"
|
|
155
156
|
},
|
|
156
157
|
"keywords": [
|
|
157
158
|
"dsh-bundle",
|
package/src/agent/council.mjs
CHANGED
|
@@ -75,8 +75,25 @@ export class CouncilRefusal extends Error {
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
/**
|
|
79
|
-
|
|
78
|
+
/**
|
|
79
|
+
* Authority bands, taken from v4.7.0: 0-49 ordinary, 50-69 captain, 70-89 org admin, 90+ system admin.
|
|
80
|
+
*
|
|
81
|
+
* ## This was a SECOND copy of a number that already existed, and the reachability check is what found it
|
|
82
|
+
*
|
|
83
|
+
* It read `export const AUTHORITY_MAX = 100;` — a literal, redeclared here. `src/agent/authority.mjs` owns
|
|
84
|
+
* that bound and the bands it belongs to, and `AUTHORITY_BAND_FLOORS` is derived from them precisely so a new
|
|
85
|
+
* band cannot leave a stale copy behind. A second literal cannot be kept in step by anything, and **the
|
|
86
|
+
* failure it produces is silent**: raise the real maximum to 120 and this module keeps refusing 101, with a
|
|
87
|
+
* message that names the wrong number as authoritative.
|
|
88
|
+
*
|
|
89
|
+
* Found by `scripts/reachability-classify.mjs`, which reported this file as a **closed loop** — a module whose
|
|
90
|
+
* only importer is the test named after it. That finding was about wiring, and the duplicated constant was
|
|
91
|
+
* sitting in the same file. **Reading the file to check the first finding is how the second one surfaced**,
|
|
92
|
+
* which is the argument for investigating a report rather than counting it.
|
|
93
|
+
*/
|
|
94
|
+
import { AUTHORITY_MAX } from './authority.mjs';
|
|
95
|
+
|
|
96
|
+
export { AUTHORITY_MAX };
|
|
80
97
|
|
|
81
98
|
/**
|
|
82
99
|
* The weight of one participant, as a pure function of the two numbers on its ballot.
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -198,7 +198,7 @@ const MAX_STAGES = 16;
|
|
|
198
198
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
199
199
|
* overrides it at runtime for tests and packagers.
|
|
200
200
|
*/
|
|
201
|
-
const PLUGIN_VERSION = '0.
|
|
201
|
+
const PLUGIN_VERSION = '0.36.0';
|
|
202
202
|
|
|
203
203
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
204
204
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|