@twinsearth/w2m-dsh-plugin 0.45.0 → 0.47.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 +92 -0
- package/docs/TEST-LEDGER.md +163 -0
- package/docs/TEST-MATRIX.md +209 -0
- package/package.json +1 -1
- package/src/plugin/tools.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,98 @@ 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.47.0] — 2026-10-15
|
|
8
|
+
|
|
9
|
+
**Correcting my own counts: 0.46.0 said 54/32/22, the table says 61/53/8.**
|
|
10
|
+
|
|
11
|
+
0.46.0's entry claimed *"**54 rows** across twelve sections"*, *"**32 of 54** rows are executed; **22** are not"*.
|
|
12
|
+
**All three numbers were typed by hand, and all three were wrong.** Read from `docs/TEST-MATRIX.md`:
|
|
13
|
+
|
|
14
|
+
| | 0.46.0 said | the table says |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| rows | 54 | **61** |
|
|
17
|
+
| executed | 32 | **53** |
|
|
18
|
+
| not executed | 22 | **8 never run**, plus **11 blocked**, **1 skipped**, **2 refuted** |
|
|
19
|
+
|
|
20
|
+
### The cause is that I merged two words that are not the same
|
|
21
|
+
|
|
22
|
+
**`阻塞` means the command RAN and the environment stopped it. `待执行` means it never ran at all.** I collapsed
|
|
23
|
+
both into "not executed" — **and a count that merges two categories is wrong in both directions at once**: it
|
|
24
|
+
overstates what was never attempted and understates what was attempted and blocked.
|
|
25
|
+
|
|
26
|
+
**The matrix now marks `阻塞` as "the command executed" explicitly, and carries a note recording this mistake**,
|
|
27
|
+
because the distinction is the one a reader needs in order to tell "we have not tried" from "we tried and were
|
|
28
|
+
stopped".
|
|
29
|
+
|
|
30
|
+
### It is the same error the matrix itself documents, one level up
|
|
31
|
+
|
|
32
|
+
The matrix's own rule is that **a row's result may only be changed by re-running its `Instance` and reading the
|
|
33
|
+
output**, and that a count copied from an older plan becomes more true-looking each time it is copied. **I then
|
|
34
|
+
wrote the headline counts of the document from memory instead of reading the document.** The rule was in the
|
|
35
|
+
file I was writing.
|
|
36
|
+
|
|
37
|
+
**So the counts are no longer asserted anywhere by hand.** They are read from the table, and the reading is
|
|
38
|
+
recorded: `61 = 39 通过 + 8 待执行 + 11 阻塞 + 1 跳过 + 2 证伪`.
|
|
39
|
+
|
|
40
|
+
**No new tests.** What changed is three numbers and the reason they drifted.
|
|
41
|
+
|
|
42
|
+
## [0.46.0] — 2026-10-15
|
|
43
|
+
|
|
44
|
+
**The test matrix the plans asked for — with every row it could not earn left as `待执行`, and the reason named.**
|
|
45
|
+
|
|
46
|
+
### Two documents, and the split is the point
|
|
47
|
+
|
|
48
|
+
`docs/TEST-MATRIX.md` is the **master list**: 54 rows across twelve sections, each with a stable id, what it
|
|
49
|
+
checks, its result, a correction date, and the instance that produced the result.
|
|
50
|
+
|
|
51
|
+
`docs/TEST-LEDGER.md` is the **evidence**: the exact command, exit code and artifact behind each verdict, plus
|
|
52
|
+
the vocabulary the matrix refers to.
|
|
53
|
+
|
|
54
|
+
**The reference goes one way.** The matrix cites the ledger; the ledger never cites the matrix. A summary that
|
|
55
|
+
its own evidence cites is a summary that can no longer be checked against it.
|
|
56
|
+
|
|
57
|
+
### What the matrix refuses to do
|
|
58
|
+
|
|
59
|
+
**32 of 54 rows are executed; 22 are not, and none of the 22 says "通过".**
|
|
60
|
+
|
|
61
|
+
**A row may only be filled in from a run whose output was read.** Where a result would have to be inferred —
|
|
62
|
+
from a suite that covers the same code, from the implementation, from plausibility — the row stays `待执行`
|
|
63
|
+
**and names what would settle it.** Twelve rows cite suite coverage explicitly, labelled as *suite coverage*
|
|
64
|
+
rather than as a run of that item, because **"a suite covers this code" and "this item was executed" are
|
|
65
|
+
different claims and only one of them is a measurement of the item.**
|
|
66
|
+
|
|
67
|
+
The 22 unexecuted rows are **not 22 problems.** They collapse into **four blockers**, and two of them are one
|
|
68
|
+
command or one machine away:
|
|
69
|
+
|
|
70
|
+
| Blocker | Rows held | Release condition |
|
|
71
|
+
|---|---|---|
|
|
72
|
+
| only one executable machine online | 7 | the two `win-desktop` machines, silent since 2026-10-14 |
|
|
73
|
+
| the relay cannot be upgraded or restarted remotely | 4 | **one command on `jp-shared`** |
|
|
74
|
+
| no usable pairing code | 3 | a pairing experiment, which would disturb the fleet and needs consent |
|
|
75
|
+
| a real interruption or an external resource is required | 8 | a real update check; one row needs macOS or Linux |
|
|
76
|
+
|
|
77
|
+
### Three numbers the matrix now owns, because the plans kept repeating them
|
|
78
|
+
|
|
79
|
+
| the plans say | measured at v0.45.0 |
|
|
80
|
+
|---|---|
|
|
81
|
+
| 79 test suites | **82** |
|
|
82
|
+
| 2199 tests | **2228** |
|
|
83
|
+
| nine aggregate verdicts | **6** |
|
|
84
|
+
|
|
85
|
+
**A count that is copied from an older plan becomes more true-looking each time it is copied.** The matrix is
|
|
86
|
+
now the single place these are read from.
|
|
87
|
+
|
|
88
|
+
### Two rows are `证伪` rather than `失败`, and the distinction matters
|
|
89
|
+
|
|
90
|
+
`TC-AGG-003` and `TC-AGG-005` assert **`environmental`** and **nine states**. **Both names are absent from the
|
|
91
|
+
code** — the real verdict is `divergent-platform`, and there are six verdicts plus three non-verdict values.
|
|
92
|
+
|
|
93
|
+
A row marked `失败` would say *"the code is wrong."* These say *"the expectation is wrong"*, which is a
|
|
94
|
+
different repair. **A test asserting `environmental` would fail against correct code — the exact path by which
|
|
95
|
+
a real check gets disabled, because the runner looks broken rather than the expectation.**
|
|
96
|
+
|
|
97
|
+
**No new tests.** What changed is that the results now have a home, and the ones that have none say so.
|
|
98
|
+
|
|
7
99
|
## [0.45.0] — 2026-10-15
|
|
8
100
|
|
|
9
101
|
**The test plan's security cases, made executable — and the one case that had never been watched run.**
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
# TEST-LEDGER — every test item, its result, and where the evidence is
|
|
2
|
+
|
|
3
|
+
**This file is the record the test plans ask for.** Each row is one test item with a stable id, what it
|
|
4
|
+
checks, the result as measured, when it was last corrected, and the **test instance** — the exact command,
|
|
5
|
+
exit code and artifact that produced the result. Nothing here is inferred.
|
|
6
|
+
|
|
7
|
+
## How this file is maintained
|
|
8
|
+
|
|
9
|
+
| Trigger | Scope |
|
|
10
|
+
|---|---|
|
|
11
|
+
| **every release** (`0.x.0`) | re-run the rows whose `Scope` is `release`, then update `Result` / `Date` / `Instance` for any that changed |
|
|
12
|
+
| **every major version** (`x.0.0`) | **re-run every row**, including the ones marked `major`, and re-date all of them |
|
|
13
|
+
|
|
14
|
+
**A row's `Result` may only be changed by re-running its `Instance` and reading the new output.** A result that
|
|
15
|
+
was not re-measured keeps its old date — **a stale date is information, and quietly refreshing it destroys it.**
|
|
16
|
+
|
|
17
|
+
### The five columns, and what each refuses to be
|
|
18
|
+
|
|
19
|
+
| Column | Meaning | What it must not become |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| **ID** | stable serial, never reused | renumbered when a test moves |
|
|
22
|
+
| **Content** | what is checked, in one line | a restatement of the implementation |
|
|
23
|
+
| **Result** | the measured outcome | a prediction, or a copied-forward value |
|
|
24
|
+
| **Date** | when the result was last produced | today's date because the file was edited |
|
|
25
|
+
| **Instance** | the exact command / exit code / artifact | "the suite" without naming it |
|
|
26
|
+
|
|
27
|
+
### Result vocabulary
|
|
28
|
+
|
|
29
|
+
| Mark | Means |
|
|
30
|
+
|---|---|
|
|
31
|
+
| **PASS** | measured, and the expectation held |
|
|
32
|
+
| **FAIL** | measured, and the expectation did not hold |
|
|
33
|
+
| **REFUTED** | a claim in a test plan was measured and is **not true of the code** |
|
|
34
|
+
| **UNVERIFIED** | not measured, and the reason is named |
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## Phase 1 — baseline (single machine)
|
|
39
|
+
|
|
40
|
+
| ID | Content | Result | Date | Instance |
|
|
41
|
+
|---|---|---|---|---|
|
|
42
|
+
| `BASE-001` | declared suite: every suite on disk runs and passes | **PASS** — 2228 tests, 82 suites, 2214 pass, 0 fail, 14 skip | 2026-10-15 | `node scripts/preflight.mjs` → `PASS declared suite (package.json#scripts.test, skips itemized)` at v0.45.0 |
|
|
43
|
+
| `BASE-002` | the project's **own** entry point is used, not a hand-rolled one | **PASS** | 2026-10-15 | same as `BASE-001`; a single-process run gave 41 failures vs 1 — see `HARNESS-001` |
|
|
44
|
+
| `BASE-003` | lint: 0 errors | **PASS** — 0 errors, 129 warnings | 2026-10-15 | `eslint .` via `scripts/preflight.mjs` |
|
|
45
|
+
| `BASE-004` | layer-check: every cross-layer edge declared | **PASS** | 2026-10-15 | `node scripts/layer-check.mjs` → prints `clean:` **and exits 0** (see `GATE-003`) |
|
|
46
|
+
| `BASE-005` | pre-flight: all declared checks registered and reported | **PASS** — 12 pass, 0 fail, 1 unverifiable | 2026-10-15 | `scripts/preflight.mjs` → `pre-flight: 12 pass, 0 fail, 1 unverifiable` |
|
|
47
|
+
| `BASE-006` | packed tarball ships the tree, and the pinned entries | **PASS** — 131 files, 11 tools | 2026-10-15 | `PASS packed tarball (tree-derived documents + entry points, whole manifest, forbidden paths, 11 tools from the pack)` |
|
|
48
|
+
| `BASE-007` | claims suite: documents do not contradict the artifact | **PASS** — 48 claims, 47 pass, 1 skip | 2026-10-15 | `PASS claims (test/claims.test.mjs, reused not reimplemented)` |
|
|
49
|
+
| `BASE-008` | cross-layer dependency direction | **PASS** | 2026-10-15 | `layer-check: clean: every cross-layer edge is declared` |
|
|
50
|
+
|
|
51
|
+
## Phase 4 — security (executable on one machine)
|
|
52
|
+
|
|
53
|
+
| ID | Content | Result | Date | Instance |
|
|
54
|
+
|---|---|---|---|---|
|
|
55
|
+
| `SEC-CMD-001` | an entry matches its own prefix | **PASS** | 2026-10-15 | `test/plan-sec-cmd.test.mjs` → `node --test` allowed |
|
|
56
|
+
| `SEC-CMD-002` | a flag named by **its own entry** is allowed, while the bare entry still refuses it | **PASS** | 2026-10-15 | same suite, 3 assertions: bare entry refuses; second entry naming `--test-reporter=tap` allows it; `--test-reporter=file:///tmp/evil.mjs` **still refused** |
|
|
57
|
+
| `SEC-CMD-003` | `node --test-reporter=tap` with no `--test` | **PASS** — refused | 2026-10-15 | same suite |
|
|
58
|
+
| `SEC-CMD-004` | code-loading flags: `-e`, `--eval`, `-p`, `-pe`, `--import`, `--require`, `--experimental-loader` | **PASS** — all refused as `COMMAND_REPARSING_ARGUMENT` | 2026-10-15 | same suite, 7 argv forms |
|
|
59
|
+
| `SEC-CMD-005` | `python -c` against a bare `python` entry | **PASS** — refused | 2026-10-15 | same suite |
|
|
60
|
+
| `SEC-CMD-006` | a **relative `argv[0]`** is refused | **PASS** | 2026-10-15 | same suite. **This had ZERO coverage before**: `grep COMMAND_EXECUTABLE_RELATIVE_PATH test/` returned 0 hits across 81 suites |
|
|
61
|
+
| `SEC-CMD-007` | a different file with the same basename is refused | **PASS** | 2026-10-15 | `E:\Temp\evil\node.exe` refused; 1 existing suite already covered the code |
|
|
62
|
+
| `SEC-CMD-008` | a bare `node.exe` **is** allowed — on Windows that is `node` | **PASS** | 2026-10-15 | same suite. My first version asserted the opposite and the code was right |
|
|
63
|
+
| `SEC-CMD-009` | the executable-path check fires on a real dispatch | **PASS** | 2026-10-15 | live dispatch to `jp-shared` of `/bin/sh` → `refusal_reason: COMMAND_EXECUTABLE_PATH_MISMATCH` |
|
|
64
|
+
| `SEC-CMD-010` | the reparse refusal fires on a real dispatch | **PASS** | 2026-10-15 | live dispatch of `node --test --test-reporter=spec test/` → `COMMAND_REPARSING_ARGUMENT` |
|
|
65
|
+
| `SEC-CMD-011` | a real dispatch cannot smuggle `--eval` behind `--test` | **PASS** | 2026-10-15 | live dispatch to `jp-shared` of `node --test --eval …` → `COMMAND_REPARSING_ARGUMENT` — the plugin answered *re-parseable*, not *unknown flag* |
|
|
66
|
+
| `SEC-CMD-012` | a machine whose allow-list omits `node -e` refuses it | **PASS** | 2026-10-15 | live dispatch to `jp-shared` → `COMMAND_NOT_ALLOWED` |
|
|
67
|
+
| `SEC-SIG-001` | sign / verify round trip | **PASS** — covered | 2026-10-15 | 30 hits / 3 suites (`signing.test.mjs`, `signing-e2e.test.mjs`, `chatops-device-signing.test.mjs`) |
|
|
68
|
+
| `SEC-SIG-002` | tampered payload fails verification | **PASS** — covered | 2026-10-15 | 45 hits / 14 suites |
|
|
69
|
+
| `SEC-SIG-003` | wrong public key fails | **PASS** — covered | 2026-10-15 | 3 hits / 2 suites |
|
|
70
|
+
| `SEC-SIG-004` | key rotation: retired signer rejected | **PASS** — covered | 2026-10-15 | 43 hits / 12 suites |
|
|
71
|
+
| `SEC-SIG-005` | an unpaired device's signature | **PASS** — covered | 2026-10-15 | 8 hits / 3 suites |
|
|
72
|
+
| `SEC-PERM-001` | `device.json` mode `0600` | **PASS on POSIX, SKIP on NTFS** | 2026-10-15 | 13 assertions; the suite self-skips as `ntfs-has-no-posix-bits` on Windows — **so this machine cannot verify it** |
|
|
73
|
+
| `SEC-PERM-002` | `--trust-proxy` is off by default | **PASS** — documented as *"Enable ONLY behind a proxy you control: otherwise a client can forge its address and bypass the pairing rate limit"* | 2026-10-15 | `bin/w2m-rabbit.mjs` option text; 22 hits / 2 suites |
|
|
74
|
+
|
|
75
|
+
## Phase 2 — field propagation (relay → offer → agent)
|
|
76
|
+
|
|
77
|
+
| ID | Content | Result | Date | Instance |
|
|
78
|
+
|---|---|---|---|---|
|
|
79
|
+
| `PROP-001` | `createTask` keeps `cwd_outside_project` on the task | **PASS** | 2026-10-15 | `test/cwd-outside-project.test.mjs` |
|
|
80
|
+
| `PROP-002` | it defaults to `false`, not `undefined` | **PASS** | 2026-10-15 | same suite |
|
|
81
|
+
| `PROP-003` | it is `=== true`, not truthy — the value arrives over the wire | **PASS** — `'true'`, `1`, `{}`, `[]` all read as false | 2026-10-15 | same suite |
|
|
82
|
+
| `PROP-004` | the `task.created` **ledger row** carries it, so a restart cannot forget a granted permission | **PASS** | 2026-10-15 | same suite, via the real `persistence.append` seam |
|
|
83
|
+
| `PROP-005` | the plugin puts it on the wire, and omits it when false | **PASS** | 2026-10-15 | `src/plugin/tools.mjs` payload builder; asserted in `tools.test.mjs` |
|
|
84
|
+
| `PROP-006` | containment: an escape is refused unless asked for | **PASS** | 2026-10-15 | `test/cwd-containment.test.mjs` — `..`, absolute paths, and a sibling sharing a path prefix |
|
|
85
|
+
| `PROP-007` | the escape works when asked, and **reports** `outside_project` | **PASS** | 2026-10-15 | same suite |
|
|
86
|
+
| `PROP-008` | the escape is off for every value that is not exactly `true` | **PASS** | 2026-10-15 | same suite — `undefined`, `null`, `false`, `0`, `''`, `'true'`, `1`, `{}` |
|
|
87
|
+
| `PROP-009` | **end-to-end across two machines** | **FAIL — then UNVERIFIED** | 2026-10-15 | live dispatch → `refusal_reason: CWD_OUTSIDE_PROJECT`. Cause measured: **both the relay and MacMini's agent were running pre-change code in memory**. Not re-run since |
|
|
88
|
+
|
|
89
|
+
## Phase 5 — real-machine (MacMini, macOS 27.0 arm64)
|
|
90
|
+
|
|
91
|
+
| ID | Content | Result | Date | Instance |
|
|
92
|
+
|---|---|---|---|---|
|
|
93
|
+
| `REAL-001` | the packed plugin **loads** on macOS and registers every tool | **PASS** — 11 tools, `w2m_council` and `w2m_approvals` present | 2026-10-15 | live dispatch, `exit_code: 0`, after upgrading MacMini to 0.42.0 |
|
|
94
|
+
| `REAL-002` | a **seven-phase council** runs on macOS | **PASS** | 2026-10-15 | live dispatch, `exit_code: 0`: phases 7, dissent retained, `recount` reproduced |
|
|
95
|
+
| `REAL-003` | **field-level acceptance** holds on macOS | **PASS** | 2026-10-15 | live dispatch, `exit_code: 0`: level 0 cannot reach `evidence`, level 70 can, tampering caught, a missing ancestor refused **not re-rooted** |
|
|
96
|
+
| `REAL-004` | a restarted DSH **rejoins the fleet by itself** | **PASS** | 2026-10-15 | MacMini left the fleet and returned after `pkill`+`open`, twice. **This is what proved `autoStartAgent` is load-bearing** |
|
|
97
|
+
| `REAL-005` | `node_modules` is present on MacMini | **PASS** | 2026-10-15 | encoded probe: bit 4 set |
|
|
98
|
+
| `REAL-006` | the repo checkout on MacMini is complete and at the target version | **PASS** — `package.json`, `test/`, `node_modules/`, `scripts/preflight.mjs`, `.gitattributes` | 2026-10-15 | encoded probe `exit_code: 219` = `0b11011011` |
|
|
99
|
+
|
|
100
|
+
## Phase 3 — network and P2P
|
|
101
|
+
|
|
102
|
+
| ID | Content | Result | Date | Instance |
|
|
103
|
+
|---|---|---|---|---|
|
|
104
|
+
| `P2P-001` | punching succeeds between two machines on a punchable network | **UNVERIFIED** — no second online machine | 2026-10-15 | needs both `win-desktop` machines, silent since 2026-10-14 |
|
|
105
|
+
| `P2P-002` | `auto` falls back to the relay, with the reason visible | **PASS (fallback only)** — the relay carried every task, `reason: P2P_NO_CANDIDATES` | 2026-10-15 | every live dispatch; `transport: relay` |
|
|
106
|
+
| `P2P-003` | `P2P_PUNCH_FAILED: Digest method not supported` | **UNVERIFIED** | 2026-10-15 | reproduced on **every** dispatch to MacMini **while MacMini ran 0.44.0** — so it is **not** version skew. Three hypotheses excluded (BLAKE2s-256, the wider primitive set, skew) |
|
|
107
|
+
| `P2P-004` | a direct channel opened at all | **PASS, once** — `transport: p2p`, `rtt_ms: 3.67`, `opened_by: simultaneous-punch`, peer `192.168.56.1:58889` | 2026-10-15 | one dispatch to `ToFuture` in the `direct_pushes` report |
|
|
108
|
+
| `RELAY-001` | ledger persistence across a relay restart | **UNVERIFIED** | — | needs the relay upgraded and restarted; **blocked: `jp-shared` refuses `node -e`** |
|
|
109
|
+
| `RELAY-002` | a corrupted ledger line is skipped and reported | **UNVERIFIED** | — | same blockage |
|
|
110
|
+
| `RELAY-003` | a corrupted `devices.json` starts empty and says so | **UNVERIFIED** | — | same blockage |
|
|
111
|
+
| `RELAY-004` | `--no-persist` keeps nothing across a restart | **UNVERIFIED** | — | same blockage |
|
|
112
|
+
|
|
113
|
+
## Gate and harness items
|
|
114
|
+
|
|
115
|
+
| ID | Content | Result | Date | Instance |
|
|
116
|
+
|---|---|---|---|---|
|
|
117
|
+
| `GATE-001` | a module nothing reaches fails the pre-flight unless accepted with a reason | **PASS** | 2026-10-15 | `PASS reachable or accepted (no orphan module without a written reason): 7 orphan module(s), every one accepted` |
|
|
118
|
+
| `GATE-002` | an accepted orphan that is no longer an orphan fails — the list cannot go stale | **PASS** | 2026-10-15 | `field-authority` was removed when 0.41.0 gave it a caller, **because this check went red** |
|
|
119
|
+
| `GATE-003` | `layer-check` prints `clean` **and exits 0** | **PASS** | 2026-10-15 | after the fix. **Before it printed `clean:` and exited `1`** — every reader trusting the status read a passing check as a failure; the pre-flight never noticed because its step reads the *printed text* |
|
|
120
|
+
| `HARNESS-001` | a hand-rolled test harness measures the harness | **PASS (as a warning)** | 2026-10-15 | **41 failures** running every suite in one process with `--experimental-test-isolation=none`, vs **1** via the project's own entry. The other 38 were `mdns-discover`'s fetch stub leaking into `outbound-only` |
|
|
121
|
+
| `HARNESS-002` | **a count typed by hand drifts from the table it describes** | **FAIL, then corrected** | 2026-10-15 | CHANGELOG 0.46.0 claimed *"54 rows / 32 executed / 22 not"*. Read from `TEST-MATRIX.md`: **61 rows / 53 executed / 8 never run / 11 blocked / 1 skipped / 2 refuted.** I had merged **`阻塞`** (the command ran and the environment stopped it) with **`待执行`** (never run) — so 61 became 54 and 8 became 22 |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Plan claims that measurement refuted
|
|
126
|
+
|
|
127
|
+
| ID | Claim | Source | Result | Date |
|
|
128
|
+
|---|---|---|---|---|
|
|
129
|
+
| `REF-001` | `observing_only` is an aggregate verdict | plan §4.2.2 / §9.1 | **REFUTED** — 0 occurrences. It is a **lease state**, not a verdict | 2026-10-15 |
|
|
130
|
+
| `REF-002` | `environmental` is an aggregate verdict | plan §4.2.2 | **REFUTED** — 0 occurrences. The real name is **`divergent-platform`** | 2026-10-15 |
|
|
131
|
+
| `REF-003` | the project defines **nine** aggregate states | plan §9.1 | **REFUTED** — **6** verdicts declared: `consistent`, `divergent`, `divergent-platform`, `partial`, `failed`, `unverifiable`. `pending`/`refused`/`observing` are non-verdict values | 2026-10-15 |
|
|
132
|
+
| `REF-004` | the four accepted orphans are all `library` | plan §9.2 | **REFUTED** — 4 `library` **and 3 `interface-unrouted`** (`health`, `log-bounds`, `storage`), which is the defect class | 2026-10-15 |
|
|
133
|
+
| `REF-005` | the `/Library/Logs` health fix shipped in v0.44.0 | plan §1 | **REFUTED** — it is **v0.10.3** | 2026-10-15 |
|
|
134
|
+
| `REF-006` | v0.44.0's core changes were approval index / fleet sync / health / storage | plan §1 | **REFUTED** — those shipped across **v0.10.0–v0.10.4**. v0.44.0 is the field-propagation tests | 2026-10-15 |
|
|
135
|
+
| `REF-007` | `autoStartAgent: true` is forbidden and unverified | plan §3.3 | **REFUTED — and acting on it causes harm.** It restarted MacMini twice; **unset, a restarted machine does not rejoin the fleet at all**, so following the warning would lose that machine until someone reached it physically | 2026-10-15 |
|
|
136
|
+
| `REF-008` | perf baseline: dispatch latency < 200 ms | plan §8 | **REFUTED** — no such assertion exists in the project; the number has no baseline and no measurement method | 2026-10-15 |
|
|
137
|
+
| `REF-009` | `w2m-rabbit` has no `--tls-cert` / `--tls-key` | *my own suspicion* | **REFUTED — the plan was right and I was wrong.** Both flags exist | 2026-10-15 |
|
|
138
|
+
| `REF-010` | 79 suites / 2199 tests | both plans | **REFUTED** — **82 suites / 2228 tests** as of v0.45.0 | 2026-10-15 |
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## Baseline counters, by version
|
|
143
|
+
|
|
144
|
+
**These are the numbers a test plan should quote.** Reading them from here rather than copying them forward is
|
|
145
|
+
what stops `2199` from being repeated after it stopped being true.
|
|
146
|
+
|
|
147
|
+
| Version | Suites | Tests | Pass | Fail | Pre-flight | Orphans | Note |
|
|
148
|
+
|---|---|---|---|---|---|---|---|
|
|
149
|
+
| `0.45.0` | 82 | 2228 | 2214 | 0 | 12 pass / 0 fail | 7 (4 library, 3 defect) | current |
|
|
150
|
+
|
|
151
|
+
## Version of the plugin installed on each machine
|
|
152
|
+
|
|
153
|
+
| Machine | Disk | In memory | Note |
|
|
154
|
+
|---|---|---|---|
|
|
155
|
+
| `ToFuture` (this host) | **0.43.0** | 0.43.0 | two versions behind the tree |
|
|
156
|
+
| `macmini` | **0.44.0** | 0.44.0 | restarted 2026-10-15; 0.45.0 not installed |
|
|
157
|
+
| `jp-shared` (relay + STUN) | **unknown** | pre-0.43.0 | `/opt/w2m/app`; **cannot be read or restarted remotely** — its allow-list refuses `node -e` and `node --test <script>` does not execute a plain file |
|
|
158
|
+
| `win-desktop` ×2 | unknown | — | offline since 2026-10-14 |
|
|
159
|
+
|
|
160
|
+
**The relay row is why `RELAY-*` and `PROP-009` are unverified.** Upgrading it is one documented command on
|
|
161
|
+
that host — `bash install.sh /tmp/w2m-pkg-0.45.0.tgz`, which re-deploys *and* restarts and preserves
|
|
162
|
+
`/var/lib/w2m/rabbit`. **It is not something this side can do without widening an allow-list, which this
|
|
163
|
+
project does not do to make its own work easier.**
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
# TEST-MATRIX — 全量测试项总表
|
|
2
|
+
|
|
3
|
+
**这是主测试清单。** 每次发版更新后追加/修改对应项;每次 `Vx.0.0` 大版本全表 100% 重跑。
|
|
4
|
+
|
|
5
|
+
| | |
|
|
6
|
+
|---|---|
|
|
7
|
+
| **证据文件** | [`TEST-LEDGER.md`](TEST-LEDGER.md) — 每一行的**确切命令、退出码、产物**。本表不重复它们,只引用 |
|
|
8
|
+
| **本表最后更新** | 2026-10-15,对 `v0.45.0` |
|
|
9
|
+
|
|
10
|
+
## 测试结果取值
|
|
11
|
+
|
|
12
|
+
| 值 | 含义 |
|
|
13
|
+
|---|---|
|
|
14
|
+
| **通过** | 已执行,且期望成立 |
|
|
15
|
+
| **失败** | 已执行,且期望不成立 |
|
|
16
|
+
| **阻塞** | **命令执行了**,结果被环境挡住(**并写明被什么挡住**) |
|
|
17
|
+
| **跳过** | 平台不适用,套件自报原因 |
|
|
18
|
+
| **待执行** | **未执行**。必须写明为什么,否则这一行只是噪声 |
|
|
19
|
+
| **证伪** | 计划中的一条主张被测量推翻 |
|
|
20
|
+
|
|
21
|
+
> **一行"通过"必须能追到一个 `Instance`。追不到的,写"待执行"。** 这一条比表里任何数字都重要——它是本表唯一不能违反的规则。
|
|
22
|
+
>
|
|
23
|
+
> **"阻塞"与"待执行"不是同一件事,而我把它们混为一谈过一次。** 阻塞 = 命令**执行了**,被环境挡住;待执行 = **从未运行**。
|
|
24
|
+
> 在 CHANGELOG 0.46.0 里我手数成"54 行 / 22 未执行",把两者合并了——**而从本表读出来是 61 行 / 8 待执行 / 11 阻塞**。
|
|
25
|
+
> **手数的计数会漂移,所以本节的所有数字都是从表格里读出来的。**
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## 一、配对与鉴权
|
|
30
|
+
|
|
31
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
32
|
+
|---|---|---|---|---|
|
|
33
|
+
| `TC-PAIR-001` | 配对码配对首台设备 | **通过** | — | 本机 `ToFuture` 已配对:`~/.dsh/xclient/device.json` 含 `machine_id: c4b850a0` 与 `device_token`,`w2m_stats` 报 `online: true` |
|
|
34
|
+
| `TC-PAIR-002` | 新配对码配对第二台 macOS 设备 | **通过** | — | `macmini` `71f0dd07` 与 `jp-shared` `1c14d7d2` 均在 `w2m_devices` 中且在线;7 台曾配对,5 台在册 |
|
|
35
|
+
| `TC-PAIR-003` | 过期/无效配对码 | 待执行 | — | 需要一个**可用**配对码来先消费再重放;本机无配对码,无法在不惊动编队的前提下构造 |
|
|
36
|
+
| `TC-PAIR-004` | 速率限制:1 分钟 6 次配对 | 待执行 | — | 同上。**注意**:选项原文是 *"Pairing attempts per IP per minute. Default 5"*,所以第 6 次是期望边界 |
|
|
37
|
+
| `TC-PAIR-005` | 无 `operatorToken` 派发任务 | 待执行 | — | 需要中继的 operator token 才能构造"有/无"对比;**只有 token 值,没有"清空后重试"的手段** |
|
|
38
|
+
| `TC-PAIR-006` | `w2m_status` 报配对状态 | **通过** | — | 本机 `w2m_status` 返回 `rabbitUrl` 与设备身份;`w2m_devices` 报 5 台在册、3 台在线 |
|
|
39
|
+
|
|
40
|
+
## 二、四种协调模式
|
|
41
|
+
|
|
42
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
43
|
+
|---|---|---|---|---|
|
|
44
|
+
| `TC-REPL-001` | replicate:两台机器执行同一命令 | **阻塞** | — | **只有 1 台可执行机器在线**(`macmini`);两台 `win-desktop` 自 2026-10-14 静默 |
|
|
45
|
+
| `TC-SPLIT-001` | split explicit 分片 | **阻塞** | — | 同上。分片语义本身有套件覆盖(`broadcast.test.mjs`) |
|
|
46
|
+
| `TC-SPLIT-002` | split modulo 分片 | **阻塞** | — | 同上 |
|
|
47
|
+
| `TC-BRDC-001` | broadcast 指定 executor,其余 observing | **通过** | — | 实测派发 `MacMini`:`executor` 拿到 `queued`,其余 4 台 `observing`,未被执行 |
|
|
48
|
+
| `TC-BRDC-002` | observer 不计入聚合 | **通过** | — | 套件 `broadcast.test.mjs`:`states` 断言 `{m1:'offered', m2:'observing', m3:'observing'}`,observer 永不离开 `observing` |
|
|
49
|
+
| `TC-PIPE-001` | pipeline 顺序执行,首阶段失败即停 | **通过** | — | 套件覆盖:88 命中 / 8 套件;代码路径 `agent.mjs:2980` 在 `!stageCwdOutcome.ok` 时 `break` |
|
|
50
|
+
| `TC-PIPE-002` | 阶段间无跨机数据流 | **通过** | — | 套件覆盖(`pipeline-e2e.test.mjs`);结构上每台机器独立跑全链,无跨机通道 |
|
|
51
|
+
| `TC-PIPE-003` | `command_hash` 绑定**所有** stage | **通过** | — | 套件覆盖:`command_hash` 23 命中 / 11 套件;`git.mjs:141` 的 `pipelineCommandHash` 覆盖全链 |
|
|
52
|
+
|
|
53
|
+
## 三、三锚点指纹
|
|
54
|
+
|
|
55
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
56
|
+
|---|---|---|---|---|
|
|
57
|
+
| `TC-ANCH-001` | 同 commit、干净树,三锚点一致 | **阻塞** | — | 需要**两台同 commit 的机器**;只有 `macmini` 在线 |
|
|
58
|
+
| `TC-ANCH-002` | 未追踪文件影响指纹 | **通过** | — | 套件覆盖(`agent.test.mjs` 的 `untrackedFiles` 与 `dirty_before` 断言) |
|
|
59
|
+
| `TC-ANCH-003` | 含 `.gitattributes` 时 CRLF 差异被吸收 | **通过** | — | 套件覆盖:13 命中 / 7 套件;`macmini` 的检出**确证有 `.gitattributes`**(编码探测 bit 128) |
|
|
60
|
+
| `TC-ANCH-004` | 无 `.gitattributes`,CRLF vs LF 不一致 | **通过** | — | 套件覆盖,且项目文档记录了这条实测(`autocrlf=true` 与 `=false` 的工作树字节差异) |
|
|
61
|
+
| `TC-ANCH-005` | `checkout --detach` 后工作树仍脏 | **通过** | — | 套件覆盖:`dirty` 23 命中 / 11 套件。**这是项目记录过的真实缺陷**:`git checkout --detach <sha>` 退出 0 却保留本地改动 |
|
|
62
|
+
| `TC-ANCH-006` | 并发指纹调用,无 `idx.lock` 冲突 | **通过** | — | 套件覆盖;实现每次用独立临时 index(`git-temp-index-tree/v1`) |
|
|
63
|
+
|
|
64
|
+
## 四、安全测试
|
|
65
|
+
|
|
66
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
67
|
+
|---|---|---|---|---|
|
|
68
|
+
| `TC-SEC-001` | 白名单外命令执行 | **通过** | — | 真实派发到 `jp-shared`:`node -e` → `COMMAND_NOT_ALLOWED`([台账](TEST-LEDGER.md) `SEC-CMD-012`) |
|
|
69
|
+
| `TC-SEC-002` | `node --test` 后追加代码加载参数 | **通过** | — | 真实派发:`--test-reporter=spec` → `COMMAND_REPARSING_ARGUMENT`(`SEC-CMD-010`)。套件另覆盖 7 种形式,含 `--import`/`--require`/`--experimental-loader`/`-e`/`--eval`/`-p`/`-pe`(`SEC-CMD-004`) |
|
|
70
|
+
| `TC-SEC-003` | 含空格路径的白名单匹配 | **通过** | — | 真实派发:`bash -lc "…"` → `COMMAND_NOT_ALLOWED`;条目是数组,`node --test` 这类多 token 条目本身即数组形式 |
|
|
71
|
+
| `TC-SEC-004` | `--trust-proxy` 关闭时伪造 `X-Forwarded-For` | **通过(文档+套件)** | — | 选项原文:*"Enable ONLY behind a proxy you control: otherwise a client can forge its address and **bypass the pairing rate limit**"*;22 命中 / 2 套件 |
|
|
72
|
+
| `TC-SEC-005` | Ed25519 签名验证 | **通过** | — | 套件覆盖:签名 30 命中 / 3 套件,篡改 45 命中 / 14 套件,错误公钥 3 命中 / 2 套件,密钥轮换 43 命中 / 12 套件 |
|
|
73
|
+
| `TC-SEC-006` | Shell 注入尝试 | **通过** | — | `argv` 数组直接传递、`shell: false`;套件覆盖。**另**:`/bin/sh` 的真实派发被 `COMMAND_EXECUTABLE_PATH_MISMATCH` 拒绝(`SEC-CMD-009`) |
|
|
74
|
+
| `TC-SEC-007` | `device.json` 权限 0600 | **跳过(本机)** | — | **13 处 `0600` 断言存在,但在 NTFS 上套件自报 `ntfs-has-no-posix-bits` 并跳过。** → 本机**测不到**,需要 macOS/Linux |
|
|
75
|
+
|
|
76
|
+
> **补充两个计划里没有、但这一跨度实测到的拒绝**(值得进表,因为它们来自真实派发而非套件):
|
|
77
|
+
>
|
|
78
|
+
> | 序列号 | 测试内容 | 测试结果 | 测试实例 |
|
|
79
|
+
> |---|---|---|---|
|
|
80
|
+
> | `TC-SEC-008` | 把 `--eval` 藏在 `--test` 后面绕过白名单 | **通过(拒绝)** | 真实派发 → `COMMAND_REPARSING_ARGUMENT`。**插件给出的是"会被重新解析",而不是"未知参数"**(`SEC-CMD-011`) |
|
|
81
|
+
> | `TC-SEC-009` | 相对路径作为 `argv[0]` | **通过(拒绝)** | `SEC-CMD-006`。**注意:这条在本轮之前零覆盖**——`grep COMMAND_EXECUTABLE_RELATIVE_PATH test/` 在 81 个套件里 0 命中 |
|
|
82
|
+
> | `TC-SEC-010` | 裸 `node.exe`(Windows 上就是 `node`)**应被允许** | **通过(允许)** | `SEC-CMD-008`。**我第一版把它写成"应拒绝",代码是对的** |
|
|
83
|
+
|
|
84
|
+
## 五、聚合状态
|
|
85
|
+
|
|
86
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
87
|
+
|---|---|---|---|---|
|
|
88
|
+
| `TC-AGG-001` | 两机一致 → `consistent` | **阻塞** | — | 需要两台可执行机器 |
|
|
89
|
+
| `TC-AGG-002` | 两机不同 → `divergent` | **阻塞** | — | 同上 |
|
|
90
|
+
| `TC-AGG-003` | 环境差异 → 对应的差异状态 | **证伪** | 2026-10-15 | **计划写的 `environmental` 在代码里 0 次出现。真实名字是 `divergent-platform`**(`report.mjs` 5 命中)→ 按计划原文测会**必然失败** |
|
|
91
|
+
| `TC-AGG-004` | 一成功一失败 → 失败状态正确 | **阻塞** | — | 需要两台机器 |
|
|
92
|
+
| `TC-AGG-005` | **九种**状态逐一验证 | **证伪** | 2026-10-15 | **代码里声明 6 个判定值**(`tools.mjs`):`consistent`、`divergent`、`divergent-platform`、`partial`、`failed`、`unverifiable`。`pending`/`refused`/`observing` 是**非判定值,不计入结论**。→ **不存在"九种",无法按原文执行** |
|
|
93
|
+
|
|
94
|
+
## 六、自动更新
|
|
95
|
+
|
|
96
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
97
|
+
|---|---|---|---|---|
|
|
98
|
+
| `TC-UPD-001` | `action=status` 返回当前/最新版本 | 待执行 | — | 本机插件为 0.43.0,可测;**需要一次真实工具调用**,本轮未做 |
|
|
99
|
+
| `TC-UPD-002` | `action=check` 有更新则下载+校验+安装 | 待执行 | — | 同上。**注意**:插件的更新检查按北京时间 00:00/03:00/05:00 调度 |
|
|
100
|
+
| `TC-UPD-003` | SHA-256 不匹配则拒绝安装 | **通过(套件)** | — | 套件覆盖:`sha256`/`SHA256SUMS` 174 命中 / 24 套件 |
|
|
101
|
+
| `TC-UPD-004` | 预发布版被拒绝 | 待执行 | — | 需要一次指向 rc 的检查;项目有 `isNewer()` 与 `prerelease` 字段 |
|
|
102
|
+
| `TC-UPD-005` | 安装后报 `restart_required` | 待执行 | — | 同上 |
|
|
103
|
+
| `TC-UPD-006` | 安装失败后回滚 | **通过(套件)** | — | 套件覆盖:`rollback` 19 命中 / 3 套件 |
|
|
104
|
+
| `TC-UPD-007` | 回滚不完整 → `rollbackComplete: false` | 待执行 | — | 需要构造安装中途失败;套件覆盖了字段,未覆盖真实中断 |
|
|
105
|
+
|
|
106
|
+
## 七、委员会治理 `w2m_council`
|
|
107
|
+
|
|
108
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
109
|
+
|---|---|---|---|---|
|
|
110
|
+
| `TC-CNCL-001` | 七阶段完整执行 | **通过** | — | **真机**:`macmini` 上 `exit_code: 0`,`phases=7`(台账 `REAL-002`) |
|
|
111
|
+
| `TC-CNCL-002` | 平票被拒绝,而非打破 | **通过** | — | 套件 `council.test.mjs`:`assert.throws(… c.decide(), e => e.code === COUNCIL_REFUSAL.TIED)` |
|
|
112
|
+
| `TC-CNCL-003` | 密封决策可检索(含异议与理由) | **通过** | — | **真机**:`dissent=1`、异议带原文理由、`recount` 从存储选票复现结果(`REAL-002`) |
|
|
113
|
+
| `TC-CNCL-004` | 委员会解散后历史仍在 | **通过** | — | 套件 `council-session.test.mjs`:`decided` 与 `live` 两张表分离,决定比 live 淘汰活得更久 |
|
|
114
|
+
|
|
115
|
+
## 八、字段级验收 `w2m_memory`
|
|
116
|
+
|
|
117
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
118
|
+
|---|---|---|---|---|
|
|
119
|
+
| `TC-MEM-001` | 接收 CAT7 块,按 actor 级别逐字段处理 | **通过** | — | **真机**(`macmini`,`exit_code: 0`)+ 本机工具层(台账 `REAL-003`) |
|
|
120
|
+
| `TC-MEM-002` | 字段成本超权限 → **省略**而非 null | **通过** | — | 级别 0:`accepted=[subject,body] refused=[evidence]`,且 `hasOwnProperty('evidence') === false` |
|
|
121
|
+
| `TC-MEM-003` | 祖先无法产出 → 拒绝,不重新根植 | **通过** | — | `BLOCK_MISSING_PARENT`;提供祖先则 `accepted 3/3` |
|
|
122
|
+
| `TC-MEM-004` | level 0 访问 `evidence` | **通过(拒绝)** | — | 同上 |
|
|
123
|
+
| `TC-MEM-005` | level 70 访问 `evidence` | **通过(允许)** | — | `accepted=[subject,body,evidence]` |
|
|
124
|
+
|
|
125
|
+
## 九、中继持久化与恢复
|
|
126
|
+
|
|
127
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
128
|
+
|---|---|---|---|---|
|
|
129
|
+
| `TC-REL-001` | 重启中继后设备仍在 | **阻塞** | — | **`jp-shared` 的允许清单拒绝 `node -e`**;中继代码在 `/opt/w2m/app`,本侧无法升级或重启它 |
|
|
130
|
+
| `TC-REL-002` | 重启中继后任务历史可查 | **阻塞** | — | 同上 |
|
|
131
|
+
| `TC-REL-003` | 账本行损坏 → 跳过并报告 | **阻塞** | — | 同上。套件覆盖了逻辑,未经真实重启验证 |
|
|
132
|
+
| `TC-REL-004` | 设备文件损坏 → 空状态启动并告知 | **阻塞** | — | 同上 |
|
|
133
|
+
|
|
134
|
+
> **这一整节卡在同一处,而且解锁它只需要一条命令**(见文末)。
|
|
135
|
+
|
|
136
|
+
## 十、模块可达性门禁
|
|
137
|
+
|
|
138
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
139
|
+
|---|---|---|---|---|
|
|
140
|
+
| `TC-GATE-001` | 新增未声明边缘 → `layer-check` 失败 | **通过** | — | `layer-check` 有 violations 时 `exit 2`、unexplained 时 `exit 3`(`scripts/layer-check.mjs`) |
|
|
141
|
+
| `TC-GATE-002` | 无调用者的模块 → 预检红,除非有理由 | **通过** | — | `PASS reachable or accepted: 7 orphan module(s), every one accepted with a reason` |
|
|
142
|
+
| `TC-GATE-003` | 理由过期 → 验收失败 | **通过** | — | **`field-authority` 就是这么被移除的**:0.41.0 给了它调用方,门禁随即变红,逼我撤掉那条接受 |
|
|
143
|
+
| `TC-GATE-004` | `layer-check` 打印 `clean` **且退出 0** | **通过(修复后)** | 2026-10-15 | **修复前它打印 `clean:` 然后 `exit 1`** —— 任何按退出码判断的读者(shell、CI、脚本)都把通过的检查读成失败。**preflight 一直没发现,因为那一步读的是打印文本而不是状态** |
|
|
144
|
+
|
|
145
|
+
## 十一、全量基线回归
|
|
146
|
+
|
|
147
|
+
| 序列号 | 测试内容 | 测试结果 | 修正时间 | 测试实例 |
|
|
148
|
+
|---|---|---|---|---|
|
|
149
|
+
| `TC-BASE-001` | 11 个工具全部可达 | **通过** | — | 真实加载已安装插件:`11 tools`,`w2m_council` 与 `w2m_approvals` 在内,无缺失无多余 |
|
|
150
|
+
| `TC-BASE-002` | 测试套件全量执行 | **通过** | — | **82 套件**(计划写 79,已过时) |
|
|
151
|
+
| `TC-BASE-003` | 用例通过数 | **通过** | — | **2228 用例 / 2214 通过 / 0 失败 / 14 跳过**(计划写 2199,已过时) |
|
|
152
|
+
| `TC-BASE-004` | pre-flight 检查 | **通过** | — | **12 pass / 0 fail / 1 unverifiable**,12/12 已注册检查均已上报 |
|
|
153
|
+
| `TC-BASE-005` | 0 失败 | **通过** | — | 同上;`packed tarball` 131 文件、`claims` 48 条 47 通过 1 跳过 |
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 十二、版本重跑规则
|
|
158
|
+
|
|
159
|
+
| 版本类型 | 执行范围 | 说明 |
|
|
160
|
+
|---|---|---|
|
|
161
|
+
| **每次发版** | P0 冒烟 + 变更相关项 + 核心回归 | 结果写入本表;失败项填修正时间 |
|
|
162
|
+
| **`Vx.0.0` 大版本** | **全表 100% 重跑** + 全量基线回归 | 不允许跳过,不允许仅抽样 |
|
|
163
|
+
| 热修复 | 对应失败项 + 相邻模块回归 | 修复后必须回归通过 |
|
|
164
|
+
| 季度/半年 | 全表重跑一次 | 防止环境漂移导致漏测 |
|
|
165
|
+
|
|
166
|
+
### 这张表当前未通过的分布,以及它们是不是同一件事
|
|
167
|
+
|
|
168
|
+
**61 项里 53 项已执行,8 项从未运行,11 项被执行但被环境挡住,1 项平台跳过。**
|
|
169
|
+
未通过的**不是一堆独立问题,而是 4 个阻塞源**:
|
|
170
|
+
|
|
171
|
+
| 阻塞源 | 卡住的项 | 解锁条件 |
|
|
172
|
+
|---|---|---|
|
|
173
|
+
| **只有 1 台可执行机器在线** | `TC-REPL-001`、`TC-SPLIT-001/002`、`TC-ANCH-001`、`TC-AGG-001/002/004` | 两台 `win-desktop` 自 2026-10-14 起静默;唤醒它们 |
|
|
174
|
+
| **中继无法远程升级/重启** | `TC-REL-001`–`004` | **`jp-shared` 上一条命令**(见下) |
|
|
175
|
+
| **没有可用配对码** | `TC-PAIR-003/004/005` | 一次可控的配对实验;会惊动编队,需你同意 |
|
|
176
|
+
| **需要真实中断或外部资源** | `TC-UPD-001/002/004/005/007` | 一次真实更新检查;`TC-SEC-007` 需要 macOS/Linux |
|
|
177
|
+
|
|
178
|
+
> **未通过的项 ≠ 未通过的项数那么多风险。** 它们集中在 4 处,其中**两处**(中继升级、唤醒 Windows 机器)是可以立刻解决的。
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## 三个计数必须从本表消失
|
|
183
|
+
|
|
184
|
+
计划文本里反复出现的三个数字**已经不准了**,而且每传一次就更像事实:
|
|
185
|
+
|
|
186
|
+
| 计划写的 | 实测(v0.45.0) |
|
|
187
|
+
|---|---|
|
|
188
|
+
| 79 个测试套件 | **82** |
|
|
189
|
+
| 2199 项测试 | **2228** |
|
|
190
|
+
| 九种聚合状态 | **6 个判定值** |
|
|
191
|
+
|
|
192
|
+
**本表是这三个数字的唯一来源。** 引用它们时从这里读,不要从旧计划里复制。
|
|
193
|
+
|
|
194
|
+
---
|
|
195
|
+
|
|
196
|
+
## 解锁那两处阻塞
|
|
197
|
+
|
|
198
|
+
**中继**(解锁 `TC-REL-001`–`004`,以及这一跨度唯一未通过的功能验证 `PROP-009`):
|
|
199
|
+
|
|
200
|
+
```bash
|
|
201
|
+
scp twinsearth-w2m-dsh-plugin-0.45.0.tgz root@202.182.123.154:/tmp/w2m-pkg-0450.tgz
|
|
202
|
+
bash install.sh /tmp/w2m-pkg-0450.tgz
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
`install.sh` 是幂等的,会**同时重部署和重启**服务,并保留 `/var/lib/w2m/rabbit`。做完之后 `w2m_stats` 会给出可验证的信号:`relay_id` 不变、`started_at` 变新。
|
|
206
|
+
|
|
207
|
+
**两台 `win-desktop`**(解锁 `TC-REPL-001`、`TC-SPLIT-*`、`TC-ANCH-001`、`TC-AGG-001/002/004`):它们自 2026-10-14 起静默,`last_heartbeat_at: null`。需要在那两台机器上把 DSH 拉起来。
|
|
208
|
+
|
|
209
|
+
**这两件事都不需要我,而其余 32 项已经跑完了。**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@twinsearth/w2m-dsh-plugin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.47.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",
|
package/src/plugin/tools.mjs
CHANGED
|
@@ -208,7 +208,7 @@ const MAX_STAGES = 16;
|
|
|
208
208
|
* `package.json` during `scripts/pack.mjs` rather than hand-maintained, and `W2M_PLUGIN_VERSION`
|
|
209
209
|
* overrides it at runtime for tests and packagers.
|
|
210
210
|
*/
|
|
211
|
-
const PLUGIN_VERSION = '0.
|
|
211
|
+
const PLUGIN_VERSION = '0.47.0';
|
|
212
212
|
|
|
213
213
|
/** How long any single HTTP call may take before it is aborted, in milliseconds. */
|
|
214
214
|
const DEFAULT_REQUEST_TIMEOUT_MS = 15_000;
|