@junghanacs/entwurf 0.38.1 → 0.40.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.
Files changed (50) hide show
  1. package/BASELINE.md +11 -4
  2. package/CHANGELOG.md +323 -0
  3. package/DELIVERY.md +34 -0
  4. package/LICENSES/node-gyp.txt +24 -0
  5. package/README.md +20 -6
  6. package/VERIFY.md +23 -4
  7. package/docs/setup-clean-host.md +43 -2
  8. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +32 -9
  9. package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-socket-path.js +56 -1
  10. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +25 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +10 -4
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +14 -0
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-receive.js +123 -0
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-send.js +259 -0
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-transport.js +80 -0
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +14 -2
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-probe.js +21 -0
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/win32-native.js +182 -0
  19. package/mcp/entwurf-bridge/dist/scripts/remote-pair-receive.js +65 -0
  20. package/mcp/entwurf-bridge/src/index.ts +38 -9
  21. package/mcp/entwurf-bridge/tsconfig.build.json +7 -0
  22. package/native/win32-x64/entwurf_win.node +0 -0
  23. package/native/win32-x64/manifest.json +45 -0
  24. package/package.json +5 -3
  25. package/pi-extensions/entwurf-control.ts +6 -1
  26. package/pi-extensions/lib/control-socket-path.js +56 -1
  27. package/pi-extensions/lib/entwurf-control-rpc.ts +32 -0
  28. package/pi-extensions/lib/meta-mailbox-body.ts +13 -4
  29. package/pi-extensions/lib/meta-session.ts +14 -0
  30. package/pi-extensions/lib/remote-pair-receive.ts +184 -0
  31. package/pi-extensions/lib/remote-pair-send.ts +325 -0
  32. package/pi-extensions/lib/remote-pair-transport.ts +81 -0
  33. package/pi-extensions/lib/socket-discovery.ts +12 -1
  34. package/pi-extensions/lib/socket-probe.ts +20 -0
  35. package/pi-extensions/lib/win32-native.js +198 -0
  36. package/run.sh +149 -1
  37. package/scripts/check-entwurf-self-address.ts +15 -4
  38. package/scripts/check-gate-qualification.ts +8 -1
  39. package/scripts/check-remote-pair-installed.ts +242 -0
  40. package/scripts/lib/remote-pair-installed-audit.ts +25 -0
  41. package/scripts/mutants/control-send-receipt.json +2 -2
  42. package/scripts/mutants/pack-install.json +28 -2
  43. package/scripts/mutants/remote-pair-display.json +53 -0
  44. package/scripts/mutants/remote-pair-installed-audit.json +28 -0
  45. package/scripts/mutants/remote-pair-receive.json +126 -0
  46. package/scripts/mutants/remote-pair-roundtrip.json +83 -0
  47. package/scripts/mutants/remote-pair-send.json +194 -0
  48. package/scripts/mutants/remote-pair-transport.json +66 -0
  49. package/scripts/mutants/win32-preview.json +215 -0
  50. package/scripts/remote-pair-receive.ts +73 -0
package/BASELINE.md CHANGED
@@ -23,7 +23,8 @@ or **unverified**. Since 0.20.0 the table also carries two qualifiers:
23
23
  runner is not a physical host, so bare **certified** still means a physical-host
24
24
  doctor green; and **NOT CERTIFIED — pending physical host** marks a rail whose
25
25
  missing evidence only a physical host can supply. That is an evidence boundary,
26
- not **UNSUPPORTED** — the deliberate never, which today is native Windows only.
26
+ not **UNSUPPORTED** — the deliberate never, which today names the native-Windows surfaces
27
+ outside the experimental preview (rows below).
27
28
 
28
29
  | Surface | Verdict | Evidence |
29
30
  |---|---|---|
@@ -43,8 +44,13 @@ not **UNSUPPORTED** — the deliberate never, which today is native Windows only
43
44
  | Doctor fail-closed on unreadable environ | Linux measured; Darwin unmeasured | Copilot launch-flag and omp identity-carrier: missing `/proc/<pid>/environ` as predicate INPUT is `UNVERIFIABLE` (non-green), not a benign note. omp distinguishes `pgrep` exit 1 (absent) from exit 2 (enumeration failed); copilot distinguishes ENOENT/ESRCH (gone) from other errno (read denied). |
44
45
  | setup on uncertified platform with harness present | named non-green | All 13 harness units ask `harness_rail_certified_platform()`; uncertified → FAIL whose wording is not "install failed". Harness-absent Darwin setup (the CI cell) can still be computed green. |
45
46
  | macOS physical-host probe | shipped, unrun on a Mac | `scripts/raw-macos-measure/` — `/bin/sh`, cells M1–M9, 3.5 s; needs neither entwurf install nor login. Still unmeasured: Darwin foreign-process environ (`ps -Eww`) and whether macOS `python3` is a CommandLineTools stub. |
46
- | WSL2 | unverified | Counts as Linux evidence, never a Windows surface (AGENTS Hard Rule 17) |
47
- | native Windows | UNSUPPORTED | Locked pending GLG; a scope decision, not an evidence gap |
47
+ | WSL2 Entwurf-only install + zero-token Pi citizen (GitHub Actions `windows-2025` runner, not a physical machine) | shape-only | Experimental, non-voting CI (not read by the release oracle): 2026-10-18, `.github/workflows/wsl2-install-surface.yml` run 39098773010 @ `b03d646` ([#78 receipt](https://github.com/junghan0611/entwurf/issues/78#issuecomment-6245947301)). Guest kernel `6.18.40.1-microsoft-standard-WSL2`, host `wsl --list --verbose` VERSION 2, guest fstype quoted raw as `ext2/ext3`. The run's packed tgz digest is equal across producer, host and guest; guest Node 24.18.1; harness-absent `setup` green with protected auth/harness state unchanged. Pi 1.3.0 (sha512 pinned to the registry integrity) wired by `setup`: one V3 record whose filename is its gid, a gid-keyed control socket with a native connect, `peer-facts` alive; only `get_state` was sent and no `agent_start` was observed. Pi creating an empty `auth.json` is not a login. It certifies no harness rail. Linux-guest runtime evidence only: not native-Windows evidence, and not a substitute for the required Linux CI jobs. |
48
+ | WSL2 delivery, non-pi harnesses, vendor turn, physical user machine | unverified | No receipt. Authentication and model turns were deliberately excluded from the CI cells' scope (not a CI impossibility); non-pi harnesses, delivery, fresh/resume and physical machines are unmeasured. |
49
+ | native Windows experimental preview: Pi citizen + `entwurf_v2` delivery (GitHub Actions `windows-2025` x64 runner, Node 24.18.1, Pi 1.3.0; ships in core 0.39.0; the evidence below is the feature-branch CI artifact at `3b65bdc`, and the released tarball's own Windows cells are preview run 39146098592 @ `551402c`) | shape-only | Released tarball: preview run 39146098592 @ `551402c` installed the core 0.39.0 tarball (sha256 `1d5693241b8c…`) and its eight cells (L0, L0c, R1, R2, T1, N1, B1, D1) PASS, with a faux model and no vendor turn. The text that follows is the earlier feature-branch receipt (same addon sha256 `9837893521ec…`, not the release pack). Experimental, non-voting CI (not read by the release oracle): 2026-10-18, `.github/workflows/windows-native-preview.yml` run 39123555360 @ `3b65bdc`, with the required `ci.yml` four jobs green at the same SHA (run 39123555224). Build: MSVC (VS 2026, toolset v145, SDK 10.0.26100.0), two builds byte-identical (`entwurf_win.node` sha256 `9837893521ec…`), imports advapi32 + kernel32 with `node.exe` the only delay-load; node-gyp 13.1.0 and the Node headers/`node.lib` pinned. The pack carries exactly the addon and its manifest; npm installed it into a sandboxed consumer prefix; Pi came from a tarball checked against its pinned SRI. Six addon cells PASS (final-component reparse and non-regular refusals on the read handle, no connect through a symlink to a pipe, one-deadline timeout with reclaim, pipe-name stability and loader refusals). B1: two `pi --entwurf-control` citizens, one V3 record each, record-derived pipes alive through the product probe, `peer-facts` alive, graceful exit with both addresses dead afterwards. D1: A's model called `entwurf_v2` toward B's garden id with a nonce; A's receipt `control-socket → sent`, B's model context and B's transcript `entwurf-message` entry from A carry it. The model is an offline pi-ai `fauxProvider`: no vendor turn and no comprehension claim. The transcript fact is the harness's assertion; the raw transcript is not archived. The run used the elevated Administrators owner branch, so user-SID-only privacy is not measured. Pi's `peerDependencies` warning was observed, not waived. Not evidence for any other harness on Windows. |
50
+ | native Windows: own pre-existing pipe-name birth refusal, record link/rename syscalls, descendant cleanup after a forced kill, cross-user, mixed elevation, remote callers, user-SID-only privacy, physical user machine | unverified | No receipt; the preview cells name these as unmeasured. |
51
+ | Remote pair (#107): one declared pi-durable pair, Linux server ↔ Linux notebook over operator SSH (feature branch, not a release) | one LIVE exchange recorded (L4, one pair, one run) | 2026-10-20, both hosts at branch commit `e632294`; that commit's exact-SHA CI run 39202248407 was green on all four jobs. B's native `entwurf_v2` → one SSH → A `remote-pair-receive` → A mailbox enqueue `2026-10-19T22-19-47-662Z-13c897.msg`; A's one reply → B inbox read at `2026-10-19T22:20:24.837Z`, with the matching nonce `107-live-20261020T071937-B-A-6e42d1`. Before the send, the selected compiled bridge hash, the post-build bridge start and the record/owner/sender joins were checked on both hosts; the user reopened both visible sessions. Receipt: [#107](https://github.com/junghan0611/entwurf/issues/107#issuecomment-6278665895). |
52
+ | Remote pair: OFF target, negative paths over real SSH, other rails, more than one pair, non-Linux hosts, GUI rendering of the received envelope | unverified | No receipt. The deterministic and installed cells (VERIFY) do not stand for these. |
53
+ | native Windows: other harnesses, `setup` and the `.sh` bins, fresh/resume, mux/Herdr/ACP, ARM64, records over 16 MiB, reparse-backed store folders | UNSUPPORTED | Outside the preview's scope by decision; the preview loader refuses an install without the Windows addon by name. |
48
54
 
49
55
  Notes the table cannot carry without becoming prose again:
50
56
 
@@ -65,7 +71,8 @@ Notes the table cannot carry without becoming prose again:
65
71
  - **macOS evidence is split, not a support claim.** The Entwurf-only install surface is
66
72
  CERTIFIED (CI) (row above); the harness rails are NOT CERTIFIED — pending
67
73
  physical host (rental remains unscheduled). The package-level `os` field stays
68
- unrestricted, and native Windows is UNSUPPORTED.
74
+ unrestricted, and native Windows is an experimental preview (core 0.39.0) with its own
75
+ named gaps (rows above), not a supported platform.
69
76
 
70
77
  **Operator acceptance rule:** on a claimed Claude host, reinstall from the released
71
78
  artifact, restart every old Claude process, open a new session, and run the doctor
package/CHANGELOG.md CHANGED
@@ -4,6 +4,329 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.40.0 - 2026-10-20
8
+
9
+ The bridge is crossed and the questions are carried forward. A person laid a bridge
10
+ between two machines, and a message sent across it to an existing sibling came back. That
11
+ crossing happened once, at pre-release branch commit `e632294`. This cut carries that
12
+ capability and its open questions, not a new two-host LIVE measurement at its own SHA. It
13
+ does not solve remote trust or remote visibility; the questions it leaves open are listed
14
+ below as questions, not as features.
15
+
16
+ ### Remote pair (#107)
17
+
18
+ - **One operator-declared pair across two hosts.** An opt-in `entwurf-remote-pair.json`
19
+ beside each host's meta-record store has exactly four keys: `remoteGardenId`, `ssh` (an
20
+ existing alias), `localGardenId` and `remotePairFile` (the other host's own file). One
21
+ file serves both directions. An absent file is off. A symlink, non-regular, unreadable
22
+ or invalid file is refused. The file is read at every send and receive and never cached.
23
+ The operator owns the connection between the hosts (a private network such as Tailscale
24
+ is recommended, not required) and SSH authentication. Entwurf installs, configures,
25
+ discovers and retries none of it.
26
+ - **Send.** `entwurf_v2` to the declared `remoteGardenId` makes exactly one `ssh -o
27
+ BatchMode=yes -o ConnectTimeout=10 <alias> entwurf remote-pair-receive --pair <file>`
28
+ call, with no shell and the claim on stdin. A declared target that also has a local
29
+ trace is refused as `remote-route-local-conflict`. A sender other than `localGardenId`
30
+ is refused as `remote-sender-not-declared`. Both refusals make zero SSH calls. An
31
+ undeclared target takes the unchanged local path. The send ends in one of three ways.
32
+ The first is the other host's receipt, quoted verbatim: an acceptance, or an error it
33
+ reported while processing (`remote-reported-error`). The second is its named refusal
34
+ before any mutation. The third is `remote-indeterminate`. A result is decided only when
35
+ the exit code and JSON kind agree. There is no retry.
36
+ - **Receive.** `entwurf remote-pair-receive` accepts only its own canonical file path
37
+ (normalized, not realpath). It refuses a `from` or `target` outside the declared pair
38
+ before any mailbox mutation and hands a match to that host's existing local `entwurf_v2`
39
+ dispatch. The compiled twin ships in the tarball
40
+ (`dist/scripts/remote-pair-receive.js`). The received envelope names the remote origin,
41
+ marks the sender's cwd as a sender-host path and carries `replyable=false`, with "reply
42
+ route declared, not probed". This display is proven for the self-fetch mailbox body
43
+ only. `entwurf_callback` stays local.
44
+ - **Trust and visibility, as built.** The trust model is same-operator SSH account trust.
45
+ The receiving host checks the declared pair. It does not cryptographically authenticate
46
+ a citizen, and it says nothing about whether the content deserves trust. The route has
47
+ no launch, fresh or resume path. For the measured self-fetch pair an OFF citizen is
48
+ undeliverable, and every other target keeps its own rail's admission. The code does not
49
+ check that the target's screen is open; owner pids, TTYs and garden-id labels are not
50
+ visibility. Delivery to an active, armed pi-durable can start a turn at once.
51
+ - **A reported error is not read as non-delivery.** When the other host's dispatch reports
52
+ an error (exit 4), the sender's first line says that an error was reported, that
53
+ delivery is not inferred from that line and that nothing was retried, and it quotes the
54
+ other host's text verbatim. That text includes its own `retry-safe: false` after a
55
+ possible write. An external source review on #107 raised this before the cut.
56
+ - **Docs.** DELIVERY ("Remote pair (#107)") owns the contract. `docs/setup-clean-host.md`
57
+ gains the operator steps (§2c) and "Applying new source to a running host": a pi-durable
58
+ host runs the compiled bridge even from a checkout, and a running bridge keeps the
59
+ modules it loaded, so neither a pull nor a green setup line shows which bytes are live.
60
+ `docs/remote-sibling-principles.md` is new; it holds the boundaries kept across hosts
61
+ and the questions below.
62
+
63
+ ### Questions carried forward
64
+
65
+ - **Is a connection the same as trust?** Today's boundary is an operator-owned SSH account
66
+ and one exactly declared pair. How should the reach of an account be told apart from
67
+ trusting the sibling that sent a message?
68
+ - **Does visibility survive a machine boundary?** Locally, the operator's visible-first
69
+ policy keeps conversation turns to siblings the user has open; that is a policy, not a
70
+ technical screen check. Across hosts, the first exchange relied on the user's own
71
+ confirmation that both sessions were open. What would observe and keep visible-first
72
+ remotely, without a hidden turn or a watcher?
73
+ - **How much can a sender know?** Acceptance is not a read, and a reply does not tell its
74
+ sender that the reply was read. How should that uncertainty be shown honestly without
75
+ retries, a third ACK, read tracking or a conversation manager?
76
+
77
+ None of these is a hidden backlog item;
78
+ [remote-sibling-principles](./docs/remote-sibling-principles.md) keeps them as open
79
+ questions. Automatic discovery, reconnection, OFF wake, hidden model turns, remote
80
+ callbacks and support for every backend or platform are not claimed.
81
+
82
+ ### Evidence boundary
83
+
84
+ - **Deterministic and installed.** T1 executor-in and T2 surface-in cells sit beside the
85
+ behavior: the real bridge over MCP stdio, with a stand-in `ssh` running the other host's
86
+ real entry under a separate HOME. `./run.sh check-remote-pair-installed --tgz <abs>`
87
+ (checkout-only) runs T2 against installed bytes and audits module realpaths, with a
88
+ checkout negative control. Six new mutant lanes (remote-pair display 3, receive 8,
89
+ roundtrip 5, send 12, transport 4, installed-audit 2): the committed set is now 1034
90
+ mutants across 79 lanes. `check:vitest` runs `check-remote-pair-installed-audit`.
91
+ - **One real exchange, at `e632294`, not at this release's SHA.** On 2026-10-20 B's native
92
+ `entwurf_v2` went over one SSH call to A's mailbox
93
+ (`2026-10-19T22-19-47-662Z-13c897.msg`). A's one reply carried nonce
94
+ `107-live-20261020T071937-B-A-6e42d1`, and B read it at `2026-10-19T22:20:24.837Z`. The
95
+ pair was two already-open pi-durable siblings on two Linux hosts, which the user
96
+ reopened visibly beforehand. Before the send, the selected compiled bridge hash, the
97
+ bridge start time after the build and the record/owner/sender joins were checked on both
98
+ hosts. That check first caught one host still on a pre-feature build, so the trial was
99
+ held until a manual build and visible resume. This is L4 (one pair, one run). It is not
100
+ a release-gate MUST and was not re-measured at this release's SHA. Unmeasured: an OFF
101
+ target, negative paths over real SSH, other rails, more than one pair, non-Linux hosts,
102
+ GUI rendering, and SSH's own known-hosts side effects. Receipt:
103
+ [#107](https://github.com/junghan0611/entwurf/issues/107#issuecomment-6278665895).
104
+ - Kill-power re-measured at this shipped SHA: none (all 1034 committed claims not re-proved,
105
+ #144).
106
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 6ac477d944c6 surface
107
+ 974e264f5879 -- `["bash","run.sh","check-tests-beside-behavior"]` 38/38 receipt
108
+ c8d59ba79b6a
109
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 3afbfb660562 surface
110
+ bc925701184b -- `["bash","run.sh","check-tests-beside-behavior"]` 37/37 receipt
111
+ 4e324810643d
112
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 3afbfb660562 surface
113
+ bc925701184b -- `["bash","run.sh","check-remote-pair-installed-audit"]` 2/2 receipt
114
+ bfa5031abc54
115
+ - **An earlier RED is kept as history.** The `check-tests-beside-behavior` group at the R2
116
+ candidate (head a7aaac7390d8 surface 07625e040df9, receipt b5d681a291f5) killed 34 of
117
+ 37: three mutants failed type-checking rather than the claim. Their replacements were
118
+ repaired and the group re-ran on the next candidate. No kill-power was carried over from
119
+ that run.
120
+ - **Static/LIVE split.** Local `check:full` is not run on this operator host and is not
121
+ counted as passed. The whole static floor is owed to this prepared SHA's exact push CI.
122
+ The earlier branch commit `e632294` passed all four jobs in run 39202248407; that is not
123
+ this SHA. The remote-pair installed gate is owed against this release's own candidate
124
+ tarball. The installed 11/11 on an earlier manually produced tarball is not this
125
+ release's evidence.
126
+ - **Local LIVE r1, this release's non-static LIVE: MUST (non-static 23) PASS=23 FAIL=0
127
+ SKIP=0 UNRUN=0; BEHAVIOR PASS=1 FAIL=0.** It ran once, 09:40:03–09:44:49 KST on
128
+ 2026-10-20, on head `de0bf03` plus this preparation's four metadata files (diff
129
+ `22d0a8b856ae`), with the candidate fingerprint (`22053b62bc0e`) equal at freeze, before
130
+ and after. The one-off driver (`15d7fb9dd49f`) ran the release gate's non-static steps
131
+ in its own order, command, environment and working directory; its 24 step lines equal
132
+ `release_gate()`'s by kind, name and argv, and that body is byte-identical to 0.39.0's.
133
+ GLG approved this shape for this cut: test-owned scratch sessions only, including
134
+ headless model turns and the gates' own close/resume, with no existing user or OFF
135
+ session as a target
136
+ ([#107](https://github.com/junghan0611/entwurf/issues/107#issuecomment-6280460022)). The
137
+ Codex step ran against a test-owned app-server in its own tmux session A (named pane pid
138
+ with its recorded start ticks, stopped by one TERM afterwards) from gate session S, with
139
+ the requested tiers `gpt-6-luna` and `openai-codex/gpt-6-luna`; that is the request, as
140
+ the step's own assertions check it, not a billing or model-identity proof. The compiled
141
+ bridge those steps spawned was rebuilt once beforehand, with GLG's approval, and matched
142
+ a private emit of this source 87/87. Receipts on the operator host:
143
+ `.tmp-verify/release-0.40.0/live-r1/` (`live.log` `4ced6b51ec03`, `steps.SHA256SUMS`
144
+ `f1b7e7b79d97`, 24 logs). It is not a local `release-gate --cut` PASS: the static step
145
+ did not run locally.
146
+ - **Still owed before the tag.** The static floor is this prepared SHA's exact push CI
147
+ (four required jobs). This release is carrier-bearing, so its candidate is the
148
+ native-Windows preview workflow's pack at the prepared SHA (release skill M3w), accepted
149
+ by the eight Windows cells and the Linux container, never a local `npm pack`; the
150
+ remote-pair installed gate runs against that same candidate. VERIFY §3.4 (the strict
151
+ `doctor-meta-bridge` on an installed 0.40.0 Claude host in a new post-install session)
152
+ follows the accepted candidate. Tag, GitHub release and npm publication each need their
153
+ own GO.
154
+ - **agy excluded from this cut.** VERIFY §3.7 (three agy doctors and a same-gid
155
+ native-push reply in a new operator conversation) is excluded by GLG's explicit decision
156
+ of 2026-10-20: unmeasured, not a PASS. It is a new decision for this cut only, not the
157
+ 0.39.0 exclusion carried over and not a standing waiver
158
+ ([#107](https://github.com/junghan0611/entwurf/issues/107#issuecomment-6280460022)).
159
+ - **Host residue after LIVE (P9).** The census counted 1934 directories owned by this
160
+ operator under `/tmp` after one stale, unused root of this repo's own prefix (16K) was
161
+ reclaimed, from 1935. The largest groups (`acp-cache-test`, `render-take-test`,
162
+ `caption-take-test`) do not match the prefixes this repo's gates mint, so their
163
+ ownership is not certified by that extractor; they were not deleted. One reparented
164
+ holder of a `/tmp` path is an unrelated editor daemon, untouched. Observation: the
165
+ memory-containment and chain gates left fresh roots of their own prefixes
166
+ (`entwurf-memguard-overlay-*`, `entwurf-chain-*`); that is a finding about those gates,
167
+ not fixed in this cut.
168
+ - **Herdr follows core.** `plugins/herdr/runtime-lock.json` returns from the published npm
169
+ 0.39.0 pin to the closed `herdr-checkout` source for this unpublished candidate, as
170
+ 0.38.1 and 0.39.0 did; the comment is re-dated only. The runtime-bootstrap gate requires
171
+ an npm-source lock to equal the checkout's package version, so an npm 0.39.0 pin cannot
172
+ sit beside package 0.40.0. There are no plugin manifest, registry pin or snapshot
173
+ changes; re-pinning the measured 0.40.0 registry bytes is a separate Herdr snapshot
174
+ after publication.
175
+
176
+ ## v2026.10.19-herdr.0.39.0 — Herdr Entwurf plugin 0.39.0
177
+
178
+ A separate Herdr plugin snapshot, not another core release: core package 0.39.0 and its
179
+ `v0.39.0` tag remain unchanged. The operator has published the core to npm.
180
+
181
+ **Reading guide (2026-10-19).** The `## 0.39.0` section below and the appendix of the
182
+ [v0.39.0 GitHub release](https://github.com/junghan0611/entwurf/releases/tag/v0.39.0) are
183
+ prepare- and cut-time text. The appendix records the tag, VERIFY §3.4 met, and §3.7 (agy)
184
+ excluded for that cut only by the operator's decision, not a PASS. Both still say npm was not
185
+ published. The publish is the later registry fact recorded in this section (`latest` 0.39.0,
186
+ published 2026-10-18T21:24:39Z, registry bytes equal to the accepted candidate). Neither the
187
+ published tarball's CHANGELOG nor the release page is amended by this snapshot.
188
+
189
+ ### Herdr plugin
190
+
191
+ - **Re-pin the published core 0.39.0 and close the checkout window.**
192
+ `plugins/herdr/runtime-lock.json` returns from the `herdr-checkout` carrier that core 0.39.0
193
+ rode to production npm source `@junghanacs/entwurf@0.39.0` with the registry's measured
194
+ sha512 (`sha512-xTRMQkSi…JY+1A==`). The plugin manifest moves 0.38.0 → 0.39.0; admission
195
+ remains Herdr >= 0.9.0 and the one-build/one-pane/Linux shape is unchanged. Core 0.38.1 got
196
+ no Herdr snapshot, so the previous npm pin is 0.38.0.
197
+ - **Pi range unchanged.** The acquired runtime still accepts Pi `>=1.3.0 <1.4`.
198
+ - **Upgrade by acquisition source, not just version.** A settled npm-source 0.38.0 installation
199
+ can rebind under the plugin README's ownership conditions. A host that installed an
200
+ intervening `herdr-checkout` candidate must explicitly deactivate by its own absolute runtime
201
+ path before reinstalling the npm-source snapshot. No operator installation or active session
202
+ is rewired by this release work.
203
+
204
+ ### Source-specific verification
205
+
206
+ - Registry metadata reports `latest` 0.39.0 and `repair` 0.12.8-repair.1, 605 files, published
207
+ 2026-10-18T21:24:39Z. The downloaded registry tarball is byte-equal to the preserved accepted
208
+ core candidate (SHA256 `1d5693241b8cd5fa827869cf15ecbf0048215c7f0b4ebb0422650b6ae2773578`,
209
+ 11254616 bytes); its independently computed sha512 and sha1 equal `dist.integrity` and
210
+ `dist.shasum`, so core make's Docker consumer of those bytes (`node:24-bookworm`, repoDigest
211
+ `node@sha256:6dac556d…`) is reused here, not repeated. A sandboxed `pi install` of the
212
+ registry package resolved its bridge inside the sandbox, recorded the registry URL with that
213
+ integrity, and listed the curated Claude anchors with `--list-models entwurf`; a sandboxed
214
+ global npm install of the same package passed its installed `check-bridge`.
215
+ - **The npm runtime swap against the real registry**, by the registry-shipped
216
+ `scripts/herdr-runtime.mjs` (byte-equal to this checkout's) in sandboxed user roots, 22/22
217
+ checks. The 0.38.0 runtime was seeded from its own committed lock (`beb5925`); the swap to
218
+ 0.39.0 took one acquisition, the cached tarball's sha512 equals the lock and its sha256 equals
219
+ both the ready journal's observed digest and the accepted candidate. The `installing` journal
220
+ carried the 0.38.0 identity as `previousRuntime` and the `runtime-ready` journal carries
221
+ `null`; when acquisition began the 0.38.0 tree was still at the active address. A manually
222
+ seeded torn swap (the active tree moved to the backup address with a half candidate in
223
+ staging; not a killed process) was restored before acquisition and reported `recovered:
224
+ torn-swap-with-candidate`. An exact re-request acquired nothing and left journal and tree
225
+ byte-identical, and the owned removal reclaimed cache, runtime and journal. The helper is a
226
+ leaf that probes no Pi, so these cells certify neither a Pi upgrade nor Herdr's
227
+ install/update relocation, harness wiring, the installed CLI's deactivate path, a model turn,
228
+ or recovery from a real kill.
229
+ - **Focused gates on the branch**, with HEAD, index and work surface unchanged across them:
230
+ `check-herdr-supply` (11 assertions), `check-herdr-plugin` (49),
231
+ `check-herdr-plugin-profile` (14), `check-herdr-runtime-bootstrap` (31),
232
+ `check-herdr-activation` (33), `check-herdr-placement` (25), `check-herdr-fresh-call` (45)
233
+ and `check-gate-manifests` (1000 committed mutants across 73 lanes validated, none executed).
234
+ `check-herdr-plugin-build` and `check-herdr-sandbox` were not run locally because they run
235
+ the operator's own herdr; they ride the pushed SHA's FULL floor in CI.
236
+ - Pending, and not claimed here: the pushed SHA's four-job CI and the public-ref
237
+ install/use/deactivate journey of this npm pin, on Herdr 0.9.5 (the binary
238
+ `scripts/fixtures/herdr-supply.json` names) with Pi 1.3.0, from the public `main` ref rather
239
+ than the tag. Earlier npm or checkout-carrier receipts cannot certify these source-specific
240
+ axes. Those outcomes are recorded in the snapshot's post-push acceptance ledger, not in this
241
+ frozen text.
242
+
243
+ ## 0.39.0 - 2026-10-18
244
+
245
+ ### Native Windows (experimental preview, #78)
246
+
247
+ - **A native-Windows Pi citizen, shape-only.** On Windows x64 the package carries a small
248
+ N-API addon (`native/win32-x64/entwurf_win.node` plus its `manifest.json`), loaded by
249
+ `pi-extensions/lib/win32-native.js` only after the manifest's schema, platform, arch,
250
+ file, sha256 and `napiVersion` 8 agree with the bytes (`ENTWURF_WIN32_UNSUPPORTED` /
251
+ `ENTWURF_WIN32_NATIVE_DRIFT` otherwise). It supplies the two primitives POSIX gets from
252
+ the OS: the record read refuses a final-component reparse point (`ELOOP`) and a
253
+ non-regular file (`ENTWURF_ENOTREG`) on the read handle itself, and the control
254
+ address is a named pipe `\\.\pipe\entwurf-<sha256(root)[:16]>-<gid>` whose
255
+ probe and RPC check the server's owner SID and connect at identification level. The
256
+ POSIX `O_NOFOLLOW` and ancestor policies are unchanged, and non-Windows hosts take the
257
+ existing POSIX branches of the shared modules; each axis's own CI and LIVE gates are
258
+ that evidence, not a claim of zero impact.
259
+ - **Wiring.** `meta-session`, `control-socket-path`, `socket-probe`, `socket-discovery`,
260
+ `entwurf-control-rpc`, `entwurf-control` and the bridge take the win32 branch through
261
+ that loader; pipe names come from records and are never stat-ed; nothing unlinks or
262
+ GCs a pipe on win32.
263
+ - **Carrier and provenance.** The release carrier is produced in CI (MSVC, `/Brepro`, two builds
264
+ compared byte-for-byte, imports exactly advapi32 + kernel32 with `node.exe` the only
265
+ delay-load, node-gyp 13.1.0 and the Node headers/`node.lib` pinned) and ships with
266
+ node-gyp's MIT notice (`LICENSES/node-gyp.txt`). `check-pack` reports the carrier as
267
+ `absent`, `pair-broken`, `invalid` or `present <sha>` through the loader's own verifier.
268
+ A Linux checkout pack is addon-less, so this release's candidate is the preview
269
+ workflow's pack at the prepared SHA (release skill M3w), not a local `npm pack`.
270
+ - **Measured scope.** windows-native-preview run 39123555360 @ `3b65bdc` on a GitHub
271
+ Actions `windows-2025` x64 runner, Node 24.18.1, Pi 1.3.0: six addon cells, then two
272
+ `pi --entwurf-control` citizens (one V3 record each, pipes alive through the product
273
+ probe, `peer-facts`, graceful exit with both addresses dead) and one garden-id
274
+ `entwurf_v2` delivery between them (`control-socket → sent`, B's model context and
275
+ transcript entry from A), with an offline pi-ai `fauxProvider`: no vendor turn.
276
+ - **Limits.** Experimental and shape-only; not a supported platform. UNSUPPORTED: other
277
+ harnesses, `setup` and the `.sh` bins, fresh/resume, mux/Herdr/ACP, ARM64, records over
278
+ 16 MiB, reparse-backed store folders. Unmeasured: the own pre-existing pipe-name birth
279
+ refusal, record link/rename syscalls, descendant cleanup after a forced kill,
280
+ cross-user, mixed elevation and remote callers, user-SID-only privacy (the runs took
281
+ the elevated Administrators owner branch), worker/environment teardown with a pipe
282
+ call in flight, and any physical user machine. Rows in BASELINE.
283
+
284
+ ### Verification
285
+
286
+ - **Windows workflows (#78).** `windows-native-probe.yml`, `-e1a.yml`, `-e1b.yml` and
287
+ `-preview.yml` are experimental and non-voting; their push triggers name the feature
288
+ branch, so on main they run only by dispatch. The release oracle still reads only the
289
+ four required `ci.yml` jobs. New gates `check-win32-preview` and
290
+ `check-pack-win32-carrier` (in `check:contracts`); one new mutant lane, `win32-preview`
291
+ (19 claims), and the carrier's 2 claims appended to the existing `pack-install` lane.
292
+ The committed set is now 1000 mutants across 73 lanes.
293
+ - **Experimental WSL2 workflow (#78).** `.github/workflows/wsl2-install-surface.yml`
294
+ installs this run's packed tgz inside a real WSL2 guest on a GitHub-hosted Windows runner,
295
+ runs a harness-absent `setup`, then births a zero-token Pi citizen (record, socket,
296
+ `peer-facts`; `get_state` only). It is not a release axis: the release oracle reads only
297
+ `ci.yml`, whose four required jobs are unchanged. It runs when the workflow file changes
298
+ on main, or by manual dispatch. No WSL2 support, harness rail or physical-machine claim.
299
+
300
+ ### Release boundary and verification
301
+
302
+ - **Implementation commits.** WSL2 `afcda79`..`9b492a4` (landed `86f0eb5`); native
303
+ Windows `95933c7`..`5da8f12`, landed with the carrier supply contract `32fcc1c`
304
+ (exact push CI 39128022109, four jobs green). The runtime proof stays on `3b65bdc`'s
305
+ own SHA. Coordinator-routed independent reviews (primary and supplemental) closed
306
+ every shipped implementation leaf.
307
+ - Kill-power re-measured at this shipped SHA: none (all 1000 committed claims not
308
+ re-proved, #144).
309
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 864e026877ca surface
310
+ 200536056020 -- `["bash","run.sh","check-win32-preview"]` 19/19 receipt b4de9e681dfb
311
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 864e026877ca surface
312
+ 200536056020 -- `["bash","run.sh","check-pack-win32-carrier"]` 2/2 receipt
313
+ c51ef11b84a6
314
+ - Earlier-candidate PARTIAL (operator-attested, not this SHA): head 3e527cdbea81 surface
315
+ 8f5cc4c34473 -- `["bash","run.sh","check-node-floor-coherence"]` 2/2 receipt
316
+ 6c0ec40a291f
317
+ - **Static/LIVE split.** Local P4/M0 `check:full` is not run on this operator host (its
318
+ FULL includes Herdr checks prohibited here) and is not counted as passed: the whole
319
+ static floor is owed to this prepared SHA's exact push CI.
320
+ - **Cut blockers.** VERIFY §3.4 (strict `doctor-meta-bridge` on an installed 0.39.0
321
+ Claude host in a new post-install session) and §3.7 (three agy doctors and a same-gid
322
+ native-push reply in a new operator conversation) need the operator and are not met by
323
+ this record; no tag or GitHub release until they are or GLG decides otherwise. npm
324
+ publication is outside the current authorization and was not performed; it needs a
325
+ separate GLG GO.
326
+ - **Herdr follows core.** `plugins/herdr/runtime-lock.json` stays on the closed
327
+ `herdr-checkout` source (comment re-dated only); no plugin manifest version, registry
328
+ pin or snapshot changes in this release.
329
+
7
330
  ## 0.38.1 - 2026-10-17
8
331
 
9
332
  ### pi-durable
package/DELIVERY.md CHANGED
@@ -571,6 +571,40 @@ same class of capability through the CLI-owned stdio lifecycle. Absence of Claud
571
571
  `FileChanged` / `asyncRewake` / `watchPaths` therefore means only that Claude's hook
572
572
  mechanism cannot be copied — it never proved Copilot had no vendor wake surface.
573
573
 
574
+ ### Remote pair (#107): one declared pair across two hosts
575
+
576
+ This is an opt-in route between two existing citizens on two hosts. Why it keeps these boundaries, and which questions it leaves open, is [remote-sibling-principles](./docs/remote-sibling-principles.md); this section owns the mechanism. It is off unless the operator places a file on each host. The operator owns the connection between the hosts (a private network such as Tailscale is recommended, not required) and owns SSH authentication and authorization. Entwurf installs, configures, discovers and retries none of it. It adds no relay, listener, queue or registry. One SSH process runs per send and then exits.
577
+
578
+ - **Declaration.** Each host has at most one `entwurf-remote-pair.json`, beside its meta-record store (`remotePairOptInPath()`: the pi agent dir, unless `ENTWURF_META_SESSIONS_DIR` moves the store and the file with it). It has exactly four keys:
579
+ - `remoteGardenId`.
580
+ - `ssh`: an existing SSH alias whose characters need no quoting.
581
+ - `localGardenId`.
582
+ - `remotePairFile`: the other host's canonical absolute path to its own file.
583
+
584
+ One file serves both directions. An absent file means off. A symlink, non-regular, unreadable or invalid file is refused. The file is read at every send and receive and never cached. The sending bridge and the SSH-spawned receive entry must resolve the same root; an override set in only one of those environments moves the file.
585
+ - **Send.** The sending host's `entwurf_v2` reads the file and then decides:
586
+ - A target other than `remoteGardenId` takes the unchanged local path.
587
+ - A declared target that also has a local trace on this host (a record in any state, or a control socket) is refused as `remote-route-local-conflict`, with zero SSH.
588
+ - A sender other than `localGardenId` is refused as `remote-sender-not-declared`, with zero SSH.
589
+ - Otherwise it spawns one `ssh -o BatchMode=yes -o ConnectTimeout=10 <alias> entwurf remote-pair-receive --pair <remotePairFile>`, with no shell and the claim on stdin.
590
+ - **Receive.** The entry accepts only when `--pair` equals its own canonical file path. Canonical means the normalized expected path, not realpath equivalence: a spelling through a symlinked home alias is refused. That file is the entry's whole scope. It refuses a `from` or `target` outside the declared pair before any mailbox mutation. A match goes to that host's existing local `entwurf_v2` dispatch, so every deliverability rule of the target's rail applies there; the measured pair used the self-fetch mailbox.
591
+ - **Outcomes.** The send ends in one of three outcomes:
592
+ - the other host's receipt, quoted verbatim (its paths are on the other host). This is either an acceptance or an error the other host reported while processing (`remote-reported-error`, exit 4). That error can follow a write, for example an enqueue whose later step threw and is reported `retry-safe: false`. The sender's header therefore claims neither non-delivery nor safety to resend; the quoted text is the fact;
593
+ - the other host's named refusal, made before any mutation: a pair mismatch (exit 3) or invalid input (exit 2);
594
+ - `remote-indeterminate`.
595
+
596
+ A result is decided only when the exit code and the JSON kind agree. There is no retry. An unanswered message stays unconfirmed. Acceptance is not a read or a reply. Neither side learns whether its last message was read unless the other side answers, and there is no third ACK.
597
+ - **Display.** The received envelope names the remote origin and route, marks the sender's cwd as a sender-host path, and carries `replyable=false`, with "reply route declared, not probed" stated separately. Display is proven only for the self-fetch mailbox body; control-socket and native-push rendering are not proven. `entwurf_callback` stays local.
598
+ - **Trust.** The model is same-operator SSH account trust. The receiving host checks the declared pair. It does not cryptographically authenticate a citizen, and the same account could claim either declared id.
599
+ - **Visibility.** For the measured self-fetch pair, delivery requires backing records, live owners and armed watches, so an OFF citizen of that rail is undeliverable. Any other target keeps its own rail-specific local admission. The remote route has no launch, fresh or resume path. The code does not check that the target's screen is open: an owner pid, a TTY or a garden-id label is not visibility. Live use addresses only siblings the user has open, and delivery to an active pi-durable can start a turn at once.
600
+ - **SSH side effects.** The transport adds exactly two options, `BatchMode=yes` and `ConnectTimeout=10`. Host-key checking, known-hosts writes and every other SSH policy remain the operator's, as configured. Their side effects on a real exchange were not measured.
601
+
602
+ Evidence:
603
+
604
+ - T1 (executor-in) and T2 (surface-in) are deterministic. T2 drives the real bridge over MCP stdio, and a stand-in `ssh` on PATH runs the other host's real entry under a separate HOME. An installed-tarball gate runs the T2 cells against installed bytes.
605
+ - One real exchange is recorded in [#107](https://github.com/junghan0611/entwurf/issues/107#issuecomment-6278665895), at branch commit `e632294` on 2026-10-20. A nonce went B→A→B between two already-open pi-durable siblings on two Linux hosts. That is L4: one pair, one run.
606
+ - Unmeasured: an OFF target, negative paths over real SSH, other rails, more than one pair, and non-Linux hosts.
607
+
574
608
  ## Recording a new claim
575
609
 
576
610
  For every matrix change, record:
@@ -0,0 +1,24 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2012 Nathan Rajlich <nathan@tootallnate.net>
4
+
5
+ Permission is hereby granted, free of charge, to any person
6
+ obtaining a copy of this software and associated documentation
7
+ files (the "Software"), to deal in the Software without
8
+ restriction, including without limitation the rights to use,
9
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the
11
+ Software is furnished to do so, subject to the following
12
+ conditions:
13
+
14
+ The above copyright notice and this permission notice shall be
15
+ included in all copies or substantial portions of the Software.
16
+
17
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
19
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24
+ OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -78,8 +78,19 @@ Plain MCP registration alone does not make a garden citizen.
78
78
  installation is **CERTIFIED (CI)**, weaker than a physical-host doctor; its native
79
79
  harness rails, ACP and mux remain **NOT CERTIFIED — pending physical host**.
80
80
  Detected harness wiring on Darwin can therefore be written while setup stays
81
- non-green. Native Windows is **UNSUPPORTED**. The package has no npm `os`
82
- restriction; that is not certification of every platform's harness rails.
81
+ non-green. WSL2: a CI runner (experimental) measured the Entwurf-only install and a
82
+ zero-token Pi citizen; general, physical-machine or harness-parity WSL2 support is **not
83
+ declared**, and delivery, other harnesses and physical machines are unmeasured. Native
84
+ Windows has an **experimental first preview**, a CI-built x64 addon that ships in core
85
+ 0.39.0 (published to npm); 0.38.1 and earlier carry no Windows addon. On a GitHub Actions
86
+ `windows-2025` x64 runner with Node 24.18.1 and Pi 1.3.0, a CI-built artifact was installed,
87
+ wired with `pi install`, birthed two Pi citizens and
88
+ delivered one garden-id `entwurf_v2` message between them, with an offline scripted model
89
+ and no vendor turn. Every other native-Windows surface (other harnesses, `setup` and the
90
+ `.sh` bins, fresh/resume, mux/Herdr/ACP, physical machines) is **not declared**; the
91
+ measured scope and its named gaps are in [BASELINE](./BASELINE.md#release-host-baseline).
92
+ The package has no npm `os` restriction; that is not certification of every platform's
93
+ harness rails.
83
94
 
84
95
  ### Native durable (pi-durable)
85
96
 
@@ -186,9 +197,9 @@ pi / pi-durable / Claude Code / Copilot / OMP / Antigravity / Codex
186
197
  | Open a new visible sibling | `entwurf_fresh_call {backend, model, task, cwd?}` | Launch receipt only; the sibling's nonce callback envelope supplies its new garden id |
187
198
  | Reopen a dormant pi citizen under its own id | `entwurf_resume_call {target}` | Separate LAUNCH and socket OBSERVATION receipts; no turn is run |
188
199
 
189
- **Delivery starts no process.** A live pi receives over its record-addressed Unix
190
- control socket; an armed self-fetch citizen (Claude Code, Copilot, OMP, pi-durable)
191
- through its mailbox; a probe-alive native-push citizen (Antigravity, Codex) through
200
+ **Delivery starts no process.** A live pi receives over its record-addressed control
201
+ address (a Unix socket; on the experimental native-Windows Pi preview, a named pipe);
202
+ an armed self-fetch citizen (Claude Code, Copilot, OMP, pi-durable) through its mailbox; a probe-alive native-push citizen (Antigravity, Codex) through
192
203
  its native conversation/thread. Dormant pi, undeliverable mailboxes, dead/indeterminate native
193
204
  push and record-less sockets reject honestly. Only control-socket dispatch takes
194
205
  the per-target lock; the other rails use their own deliverability/probe evidence.
@@ -201,6 +212,8 @@ receipt. `wants_reply` is etiquette, not waiting, polling or ownership; replyabi
201
212
  is a live rail fact, not merely a consequence of trusted identity.
202
213
  [DELIVERY](./DELIVERY.md#control-socket-acceptance-boundaries-120) owns these distinctions.
203
214
 
215
+ **One declared remote pair (opt-in, #107).** The operator places an `entwurf-remote-pair.json` on each of two hosts. Then `entwurf_v2` to the declared remote garden id runs the other host's `entwurf remote-pair-receive` once over the operator's own SSH, and that host checks the pair and dispatches locally. The trust is the same operator's SSH account. It makes one attempt with no retry, and it uses no relay or listener. [DELIVERY](./DELIVERY.md#remote-pair-107-one-declared-pair-across-two-hosts) owns the contract; [setup](./docs/setup-clean-host.md#2c-optional-remote-pair-between-two-hosts-107) covers the operator steps.
216
+
204
217
  **Mux launches; it never delivers.** Inside Herdr, fresh opens a new unfocused tab
205
218
  in the caller's workspace, pi/Claude Code only, with no tmux fallback. Outside,
206
219
  it opens pi/pi-durable/Claude Code/Copilot/OMP/Codex visibly on the caller's own tmux
@@ -226,7 +239,8 @@ and [Herdr launch](https://github.com/junghan0611/entwurf/blob/main/docs/herdr-l
226
239
 
227
240
  The pi adapter registers the compiled bridge with Pi's built-in MCP after record
228
241
  birth; Pi supervises the MCP child. **MCP is ingress; pi receive remains the
229
- record-addressed Unix control socket.** Garden identity and dispatch stay Entwurf's.
242
+ record-addressed control address (a Unix socket, or the native-Windows preview's named
243
+ pipe).** Garden identity and dispatch stay Entwurf's.
230
244
  Codemode is harness-internal, not another garden citizen.
231
245
 
232
246
  ## Operation guides
package/VERIFY.md CHANGED
@@ -209,6 +209,16 @@ that moved out of `scripts/` and into a file beside its subject would otherwise
209
209
 
210
210
  Do not collapse source, package, fixture, and native-host evidence into one “green.”
211
211
 
212
+ **Remote pair (#107).** Each layer of evidence lives in its own place:
213
+
214
+ - **Deterministic.** The cells sit beside the behavior in `pi-extensions/lib/remote-pair-*.test.ts` and are found by `check-tests-beside-behavior`. T1 is executor-in. T2 is surface-in: the real bridge over MCP stdio, with a stand-in `ssh` on PATH that runs the other host's real `run.sh` under a separate HOME. Both are offline.
215
+ - **Installed bytes.** `./run.sh check-remote-pair-installed --tgz <abs>` is checkout-only and takes a caller-supplied candidate tarball. It installs a sandboxed copy, checks the compiled surface, and runs the T2 cells against the installed subject. It also audits that every module those processes load resolves inside the consumer prefix, with a checkout negative control. Its audit primitive is mutation-qualified as `check-remote-pair-installed-audit` inside `check:vitest`.
216
+ - **Real two-host exchange (T3).** This is opt-in operator LIVE evidence, recorded in [BASELINE](./BASELINE.md) and #107. It is not a release-gate MUST and not a fixture that needs a second machine online. A T1, T2 or installed green does not stand for it, and its record belongs to the commit it ran on; a later SHA does not inherit it. Re-run T3 when any of these change:
217
+ - the SSH argv or quoting;
218
+ - the receive entry's layout, stdout or exit codes;
219
+ - the declaration schema or root resolution;
220
+ - either host's Node or Pi.
221
+
212
222
  **Native durable contact (#129, #130 carrier).** Three deterministic beside-test/mutant
213
223
  coordinates in `check:contracts` split the durable contact by the file that carries each claim's QK
214
224
  (#144): a carrier or native-module mutant runs its one file, the rest run four. `check-pi-durable-beside` holds the adapter, the installed
@@ -276,14 +286,16 @@ caller/target/cross-harness LIVE are owed by `smoke-pi-durable-fresh-live`, a re
276
286
  | Linux artifact consumer | required `check-install-container` CI job against one preserved candidate | Fixtures prove package/oracle shape, not a real Claude lifecycle. |
277
287
  | Exact release commit | the exact SHA's push run: all four required CI jobs green (the qualification body is not read, #144) | A different green SHA is not transferable evidence. |
278
288
  | macOS Entwurf-only install | required `macos-install-surface` CI job at the exact release SHA | Shape-only, CERTIFIED (CI): certifies the Entwurf-only install path on macOS only — never Claude/Copilot/OMP/agy wiring, the pi rail, ACP or mux. Promoted from non-voting (`continue-on-error`) to required in 0.20.0 after its first CERTIFIED (CI) green on a GitHub Actions `macos-latest` runner (not a physical host): run 34303884286 @ `70eda03` (2026-09-09), 65s, all 10 steps success — the packed candidate installed clean, `entwurf --help` and `entwurf check-bridge` ran (the latter listing the seven `entwurf-bridge` MCP tools of that date; eight today), an all-harness-absent `entwurf setup` reached `result: green` across the five documented SKIP probes (`pi`/`claude`/`agy`/`copilot`/`omp`), and five checked paths (`.pi`, `settings.json`, `.gemini`, `.copilot`, `auth.json.bak`) plus a byte-identical `auth.json` proved zero harness/credential writes. A macOS runner failure now blocks every release cut, the same as any other required job. |
289
+ | Native-Windows carrier (carrier-bearing release, from 0.39.0) | one `windows-native-preview.yml` dispatch at the exact prepared SHA after its four `ci.yml` jobs are green: accepted build receipt (two byte-identical MSVC builds, exact import set), `pack` printing `present`, eight Windows addon/citizen cells on the installed tarball; that run's `win32-preview-tgz` is the release candidate, retrieved (never packed locally) with its `SHA256SUMS`, the Windows-printed install hash and the downloaded hash equal, then accepted by the Linux `check-install-container` unchanged (release skill M3w) | Experimental, shape-only, non-voting for `ci.yml`: no vendor turn, x64 runner only, named gaps in BASELINE. The four `ci.yml` jobs (incl. macOS) saw an addon-less pack, so the carrier-bearing tarball's macOS install is unmeasured. Artifacts expire after 14 days; the preserved copy is the durable one. |
279
290
  | LIVE runtime | `LIVE=1 ./run.sh release-gate <scratch> --cut` plus any shipped on-demand backend axis | `--cut` enforces `SKIP=0`; a red wired gate blocks the cut. |
280
291
  | Native Claude host | installed strict doctor against a new real session | Missing live join is `NOT CERTIFIED`, not a fixture PASS. |
281
292
  | Native agy host | three doctors plus conversation-id-gated native-push round trip | Aggregate release-gate does not own an agy conversation id. |
282
293
  | Native Codex host | caller-seat topology accepted 2026-09-16 (56 assertions, exit 0); caller-DIRECTORY axis accepted the same day (65 assertions, exit 0) | Operator-owned birth/MCP/statusline/terminal-title atoms and the on-demand four-coordinate chain are measured on Linux at Codex 0.153.4: the app-server alone in session A (`$30/@41/%45`, pid 737636), and initial Pi / omitted-placement fresh Codex / Codex-opened outbound Pi all in a different session S (`$2`, `@46`/`@47`/`@48`; `@58`/`@59`/`@61` in the lane C run); exact callbacks and addressed delivery both ways. A ≠ S is the load-bearing half — the app-server's inherited `TMUX` names A, so the outbound Pi landing in S can only have come from the caller's own pane title, and its receipt records `seat-source=codex-title-anchor`. **#95 lane C added the second axis to the same card: WHERE the sibling starts.** Hop 1 joins four authorities that cannot borrow from each other — the pane's `#{pane_current_path}`, the vendor rollout's `session_meta.cwd`, the Entwurf record and the requested scratch — and hop 1's leg requests a cwd while hop 2 requests NONE, so hop 2's directory can only come from the Codex caller's own record; both are asserted different from the app-server's live `/proc/<pid>/cwd`. 65 and 56 are different contracts, not a regression. The 2026-09-12 fixed-home chain is PAST CONTRACT (#95 D1); `DELIVERY.md` owns every receipt and digest. Placement beside a TUI whose thread nobody named is unsupported and unclaimed. |
283
294
 
284
295
  The repo-local `entwurf-release` skill owns the `land → prepare → make → publish`
285
- state machine. Each mode is a separate GLG authorization. Preserve one candidate,
286
- accept and publish those exact bytes without repacking, and record its digest and
296
+ state machine. Each mode is a separate GLG authorization. Preserve one candidate
297
+ (for a carrier-bearing release, the one retrieved from the preview run, never a local
298
+ pack), accept and publish those exact bytes without repacking, and record its digest and
287
299
  consumer image outside this standing protocol.
288
300
 
289
301
  ### Verifying the two capabilities a gate cannot fully judge
@@ -385,6 +397,13 @@ not certified, a detected harness is named non-green (FAIL) whose wording is
385
397
  not an install failure: the wiring WAS written, but the rail is NOT CERTIFIED —
386
398
  pending physical host. That FAIL is the honest setup verdict, not a skip.
387
399
 
400
+ WSL2: a separate experimental workflow (`.github/workflows/wsl2-install-surface.yml`)
401
+ measures the Entwurf-only install and a zero-token Pi citizen inside a real WSL2 guest on
402
+ a GitHub-hosted Windows runner. The release oracle does not read it
403
+ (`verify-exact-ci.sh` selects only `ci.yml` runs), so it is not a release axis and a red
404
+ there blocks no cut. It runs when that workflow file changes on main, or by manual
405
+ dispatch. Recorded in [BASELINE.md](./BASELINE.md).
406
+
388
407
  ### 1.1 Variables (optional)
389
408
 
390
409
  ```bash
@@ -419,7 +438,7 @@ mailbox with `origin=pi-session`, `replyable=true`).
419
438
 
420
439
  ### 1.4 Cross-install / cross-backend parity (optional, high-value)
421
440
 
422
- Compare a fresh self-awareness report across axes: (1) same backend, different install path — answer must be path-invariant; (2) same backend, different machine — identical native tool list + MCP server/tool set; (3) different backend, same bridge — same garden capability but **different** native tool surface (a Claude session reporting another backend's native tools is a fail); (4) native pi routing vs ACP-bridged, same model — the native pi citizen reaches the compiled `entwurf-bridge` through Pi's built-in MCP (`mcp__entwurf_bridge__<verb>`, six active tools and two hidden), while the ACP backend reaches that bridge through the explicit `entwurfProvider.mcpServers` projection in its own callable dialect (see §2.1). Compare the actual ingress provenance and backend-native tools, not an assumed absence of MCP on pi; receive to the pi citizen remains its record-addressed Unix control socket. Honest "I cannot tell" hedging is preferable to inventing provenance. This is the current #125 comparison criterion, not a newly measured parity receipt. agy is graded by its native-citizen checklist, not by pretending it has an ACP overlay.
441
+ Compare a fresh self-awareness report across axes: (1) same backend, different install path — answer must be path-invariant; (2) same backend, different machine — identical native tool list + MCP server/tool set; (3) different backend, same bridge — same garden capability but **different** native tool surface (a Claude session reporting another backend's native tools is a fail); (4) native pi routing vs ACP-bridged, same model — the native pi citizen reaches the compiled `entwurf-bridge` through Pi's built-in MCP (`mcp__entwurf_bridge__<verb>`, six active tools and two hidden), while the ACP backend reaches that bridge through the explicit `entwurfProvider.mcpServers` projection in its own callable dialect (see §2.1). Compare the actual ingress provenance and backend-native tools, not an assumed absence of MCP on pi; receive to the pi citizen remains its record-addressed control address (a Unix socket; a named pipe on the experimental native-Windows Pi preview). Honest "I cannot tell" hedging is preferable to inventing provenance. This is the current #125 comparison criterion, not a newly measured parity receipt. agy is graded by its native-citizen checklist, not by pretending it has an ACP overlay.
423
442
 
424
443
  **Cortex on axis 3.** A cortex session must expose the same garden capability
425
444
  while keeping cortex's own native tool surface. Its callable MCP identifier shape is
@@ -518,7 +537,7 @@ Pass: user/assistant turns accumulate normally; the transcript is not broken/emp
518
537
  The minimum passing bar:
519
538
 
520
539
  1. **Deterministic floor green:** `pnpm run check:full` passes (the core tier plus the hermetic-integration and package/install tiers, incl. `check-pack`), in the exact-SHA CI push run of the same prepared candidate (criterion 2's run). The qualification body is not a criterion (#144).
521
- 2. **All four required CI jobs green on the exact release commit:** `check`, `install-surface`, the required Linux `artifact-consumer`, and `macos-install-surface` — promoted from non-voting to required in 0.20.0 (see the release acceptance axes table above for what its green run does and does not certify); preserve the Linux artifact-consumer's tarball digest and image identity. A macOS runner failure now blocks the cut like any other required job.
540
+ 2. **All four required CI jobs green on the exact release commit:** `check`, `install-surface`, the required Linux `artifact-consumer`, and `macos-install-surface` — promoted from non-voting to required in 0.20.0 (see the release acceptance axes table above for what its green run does and does not certify); preserve the Linux artifact-consumer's tarball digest and image identity. For a carrier-bearing release those CI tarballs are addon-less and are NOT the release candidate: the exact release bytes are the M3w-retrieved preview tarball, accepted separately by the eight Windows cells and the Linux container (axes row "Native-Windows carrier"). The four-job floor, macOS included, is unchanged. A macOS runner failure now blocks the cut like any other required job.
522
541
  3. **Live floor MUST green:** `LIVE=1 ./run.sh release-gate <dir> --cut` exits 0 reporting `MUST PASS=N FAIL=0 SKIP=0`; with `--cut` a single SKIP is red, so the exit code itself now carries this condition. A BEHAVIOR FAIL is advisory, not blocking.
523
542
  4. **Native-host doctor green where the Claude meta-bridge is claimed:** a new post-install Claude session exists, live evidence is present, and the installed `doctor-meta-bridge` exits 0. `NOT CERTIFIED` is a release failure for that host, not a skip.
524
543
  5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge` as the single MCP server with its eight current tools, and presents a backend-native (not normalized) tool surface.