@junghanacs/entwurf 0.15.1 → 0.16.1
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/AGENTS.md +1 -1
- package/CHANGELOG.md +354 -0
- package/DELIVERY.md +3 -2
- package/README.md +68 -88
- package/VERIFY.md +4 -1
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +147 -9
- package/docs/setup-clean-host.md +125 -6
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +65 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +19 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +17 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +172 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +152 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +271 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +988 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-receive-omp.js +574 -0
- package/mcp/entwurf-bridge/dist/scripts/omp-receive-facts.js +84 -0
- package/mcp/entwurf-bridge/src/index.ts +65 -19
- package/mcp/entwurf-bridge/tsconfig.build.json +19 -3
- package/mcp/tsconfig.json +10 -0
- package/package.json +19 -9
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/meta-bridge-omp/entwurf-meta-omp/package.json +7 -0
- package/pi/omp-receive/entwurf-receive-omp/package.json +7 -0
- package/pi-extensions/entwurf-control.ts +12 -9
- package/pi-extensions/lib/acp/backend-adapter.ts +19 -9
- package/pi-extensions/lib/acp/backend.ts +125 -7
- package/pi-extensions/lib/acp/claude-acp-launch.js +100 -0
- package/pi-extensions/lib/entwurf-self-address.ts +18 -7
- package/pi-extensions/lib/meta-sender-identity.ts +1 -1
- package/pi-extensions/lib/meta-session.ts +219 -5
- package/pi-extensions/lib/mux-fresh-call.ts +171 -17
- package/pi-extensions/lib/omp-fresh-preflight.ts +275 -0
- package/pi-extensions/meta-bridge-omp.ts +1244 -0
- package/pi-extensions/meta-bridge-receive-omp.ts +666 -0
- package/run.sh +399 -31
- package/scripts/check-acp-launch-namespace.ts +127 -0
- package/scripts/check-acp-prompt-lifecycle.ts +145 -2
- package/scripts/check-copilot-birth-hook.ts +28 -1
- package/scripts/check-entwurf-self-address.ts +31 -0
- package/scripts/check-gate-qualification.ts +7 -3
- package/scripts/check-harness-admission-parity.ts +143 -0
- package/scripts/check-meta-doctor-oracle.sh +20 -0
- package/scripts/check-omp-birth-hook.ts +1049 -0
- package/scripts/check-omp-fresh-preflight.ts +208 -0
- package/scripts/check-omp-receive-arm.ts +516 -0
- package/scripts/check-setup-qualification.sh +40 -2
- package/scripts/copilot-bridge-oracle.sh +14 -6
- package/scripts/fake-copilot-vendor.sh +4 -2
- package/scripts/inventory-verification-surface.ts +1 -1
- package/scripts/meta-bridge-hook-log.sh +9 -1
- package/scripts/mutants/acp-launch-namespace.json +34 -0
- package/scripts/mutants/acp-prompt-lifecycle.json +67 -2
- package/scripts/mutants/copilot-birth.json +10 -10
- package/scripts/mutants/mux-fresh-call.json +22 -22
- package/scripts/mutants/omp-birth.json +173 -0
- package/scripts/mutants/omp-fresh.json +300 -0
- package/scripts/mutants/omp-receive.json +135 -0
- package/scripts/mutants/pack-install.json +2 -2
- package/scripts/mutants/self-address.json +34 -0
- package/scripts/mutants/setup-verdict.json +35 -0
- package/scripts/omp-bridge-doctor.sh +315 -0
- package/scripts/omp-bridge-install.sh +221 -0
- package/scripts/omp-bridge-oracle.sh +154 -0
- package/scripts/omp-bridge-uninstall.sh +57 -0
- package/scripts/omp-config-xdev.py +310 -0
- package/scripts/omp-config-xdev.sh +76 -0
- package/scripts/omp-mcp-bridge.sh +320 -0
- package/scripts/omp-mcp-config.py +392 -0
- package/scripts/omp-receive-doctor.sh +246 -0
- package/scripts/omp-receive-facts.ts +106 -0
- package/scripts/omp-receive-install.sh +228 -0
- package/scripts/omp-receive-uninstall.sh +60 -0
- package/scripts/omp-tool-surface.py +400 -0
- package/scripts/raw-acp-child-exit-measure/README.md +285 -0
- package/scripts/raw-acp-child-exit-measure/acp-turn-population.py +89 -0
- package/scripts/raw-acp-child-exit-measure/reaper-correlation.py +47 -0
- package/scripts/raw-omp-measure/README.md +420 -0
- package/scripts/raw-omp-measure/probe-extension.ts +76 -0
- package/scripts/raw-omp-measure/probe-receive-surface.ts +250 -0
- package/scripts/raw-omp-measure/source-audit.md +414 -0
- package/scripts/smoke-omp-bridge-state.sh +221 -0
- package/scripts/smoke-omp-fresh-live.ts +497 -0
- package/scripts/smoke-omp-mcp-state.sh +327 -0
- package/scripts/smoke-omp-receive-live.ts +340 -0
- package/scripts/smoke-omp-receive-state.sh +196 -0
- package/scripts/smoke-setup-verdict.sh +48 -3
- package/scripts/tsconfig.json +2 -0
package/AGENTS.md
CHANGED
|
@@ -182,7 +182,7 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
182
182
|
- Every `.ts` file belongs to one typecheck fence: root emit-capable config, MCP strip-types config, or scripts strip-types config. Do not hide files with `exclude`.
|
|
183
183
|
- Root pi extensions import TypeBox through `@earendil-works/pi-ai`; do not mix direct `@sinclair/typebox` types.
|
|
184
184
|
- MCP/scripts use explicit `.ts` imports where Node strip-types requires them. Installed operator surfaces route to compiled JS.
|
|
185
|
-
- pi runtime range is `>=0.84.
|
|
185
|
+
- pi runtime range is `>=0.84.4 <0.85` with devDep exact `0.84.4`; re-evaluate loader aliases and `/compat` at every minor ceiling. The ceiling moves on measurement, never on assumption, and a previous bump's argument is never reused: at 0.83.0→0.84.0 `compat.ts` was still byte-identical but `loader.ts` was NOT, so the diff itself had to be read and judged reachable-or-not. Per-bump hashes, diff judgments, and reachability findings live in the ROADMAP **Dep bump(별도 트랙)** ledger — keep them there, not here.
|
|
186
186
|
- ACP pins are recorded in `package.json` and checked by `check-dep-versions`/`check-acp-sdk-surface`; do not describe a dependency bump as a behavioral fix without evidence.
|
|
187
187
|
|
|
188
188
|
## Working Style
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,360 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.16.1 - 2026-09-01
|
|
8
|
+
|
|
9
|
+
### Verification
|
|
10
|
+
|
|
11
|
+
Each receipt carries its own scope; none of them is transferable to another commit or host.
|
|
12
|
+
|
|
13
|
+
- **`pnpm run check:full`** — PASS, exit 0, **454s** inside the gate, on the 0.16.1
|
|
14
|
+
versioned tree (HEAD `2e7ceb4` + the uncommitted changelog/version edits).
|
|
15
|
+
- **`./run.sh check-gate-qualification`** — **335/335 KILLED, NOT KILLED 0**, as the
|
|
16
|
+
release-gate MUST step. The first run of this cut reported **334/335**: the single
|
|
17
|
+
miss was `PACK-INSTALL-PIN-MATCHER-BOUNDED` reading `MUTANT-STALE` because `5c1bda5`
|
|
18
|
+
moved `run.sh`'s pin matcher to the 0.84.4 floor and left that mutant's anchor on
|
|
19
|
+
0.84.3, so it matched 0× and the gate had silently stopped asking its question.
|
|
20
|
+
Repaired in `2e7ceb4` and re-run green. A rotted anchor is recorded here rather than
|
|
21
|
+
quietly fixed, because "N killed" only means something when N is the whole set.
|
|
22
|
+
- **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.16.1.m0LUjr --cut`** —
|
|
23
|
+
**MUST: PASS=23 FAIL=0 SKIP=0**, **BEHAVIOR: PASS=1 FAIL=0 SKIP=0**. Log at
|
|
24
|
+
`/tmp/entwurf-release-gate-0.16.1.m0LUjr/release-gate.log`. `smoke-mux-lifecycle-live`
|
|
25
|
+
failed the first run on a pi-native nonce callback that never arrived inside its 300s
|
|
26
|
+
window (the codex rail was measured healthy at the time: 5h 23%, weekly 77%), and
|
|
27
|
+
passed on re-run — recorded because a LIVE step that needed a retry is not the same
|
|
28
|
+
evidence as one that passed first time.
|
|
29
|
+
- **#72 launch/observation receipts** — the launcher's two field claims are not
|
|
30
|
+
unit-provable, so they were measured on the host that produced the failure:
|
|
31
|
+
`/proc/<pid>/cmdline` carries no vendor name, the janitor's own Phase 1 selector run
|
|
32
|
+
against the real `ps` row with its age threshold forced to 0 selects nothing, and a
|
|
33
|
+
real SIGTERM still ends at exit 0 with the frame on stderr. Commands and output in
|
|
34
|
+
`scripts/raw-acp-child-exit-measure/README.md`.
|
|
35
|
+
|
|
36
|
+
### Added
|
|
37
|
+
|
|
38
|
+
- **`setup` composes OMP — the fifth backend is now in the one command.** v0.16.0 admitted OMP
|
|
39
|
+
as a D6 citizen with installers, doctors and inverses for every unit, but `setup_all` had no
|
|
40
|
+
`omp` branch: on an operator host the released package printed a **green** setup summary while
|
|
41
|
+
OMP had nothing installed — no extension, no `mcp.json` entry, no garden id on the status line.
|
|
42
|
+
Presence-driven now, same shape as Copilot: `omp` on PATH composes four independent named
|
|
43
|
+
components (birth → MCP hand → the `tools.xdev` operator setting → receiver), absent is one
|
|
44
|
+
zero-state SKIP, and a detected-but-incomplete unit is a named FAIL owning a nonzero exit.
|
|
45
|
+
Gate: `smoke-setup-verdict` S-8 drives the real composition against a stub vendor and asserts
|
|
46
|
+
every install-state, both extension units in the sandbox agent dir, the effective `xdev-off`
|
|
47
|
+
reading, and idempotence on a second run; S-1 pins `OMP_BIN` absent and requires the SKIP row.
|
|
48
|
+
- **`install-omp-config` / `uninstall-omp-config` — the operator setting is a unit, not a
|
|
49
|
+
documentation step.** `tools: xdev: false` was a hand-edit in `docs/setup-clean-host.md`, so a
|
|
50
|
+
host that skipped it registered every entwurf tool behind the vendor's `xd://` wrapper and the
|
|
51
|
+
doorbell announced a tool the model could not call. The writer owns exactly the lines it adds
|
|
52
|
+
(recorded in its install-state), refuses a symlinked config, refuses a config it cannot parse,
|
|
53
|
+
and refuses an EXPLICIT operator `tools: xdev: true` **by name** rather than overwriting a
|
|
54
|
+
decision — setup surfaces that as a component FAIL for the operator to resolve. The inverse
|
|
55
|
+
takes back only the recorded lines and refuses when the file changed since install.
|
|
56
|
+
- **`docs/adding-a-harness.md` step 10 — an onboarding is not finished until `setup` composes
|
|
57
|
+
it.** The rule the OMP gap forced, with the five conditions a new harness owes (presence-only
|
|
58
|
+
trigger, one independent component row per unit, compose only what an inverse can undo,
|
|
59
|
+
operator settings are units with a refusing writer, pin the probe seam and add an aggregate
|
|
60
|
+
cell) and the shape to watch for: two closed parity loops with no gate owning the edge between
|
|
61
|
+
them.
|
|
62
|
+
|
|
63
|
+
### Changed
|
|
64
|
+
|
|
65
|
+
- **pi floor moved to 0.84.4.** devDependency exact pin, the three peer ranges (`>=0.84.4 <0.85`),
|
|
66
|
+
the `check-pack-install` runtime pins, the pin-leak matcher's version boundary with its synthetic
|
|
67
|
+
fixture, and the pnpm lockfile all move together — the floor is one fact with several spellings,
|
|
68
|
+
and a partial bump is how they drift apart.
|
|
69
|
+
|
|
70
|
+
### Fixed
|
|
71
|
+
|
|
72
|
+
- **#72 — the ACP Claude child is no longer selected by the host janitor that was killing it, and
|
|
73
|
+
a caught signal survives the vendor erasing it.** The child was not crashing: it was being **SIGTERMed from outside**. A
|
|
74
|
+
janitor installed on the operator's host for a *different* harness (openclaw's acpx, upstream
|
|
75
|
+
PR #245) selects the vendor process name `claude-agent-acp` by **argv substring** and kills
|
|
76
|
+
anything older than 900s. entwurf **retains** its child across turns, so that child's age is the
|
|
77
|
+
age of the SESSION, not of a turn — every session past 15 minutes was shot at every 5 minutes.
|
|
78
|
+
The vendor's own handler then turned the signal into `dispose(); process.exit(0)`, so the death
|
|
79
|
+
reached entwurf as exit code 0 with no signal, indistinguishable from a clean shutdown. That is
|
|
80
|
+
why three diagnosis passes retired four candidate causes and still missed it. Measured: **12 of
|
|
81
|
+
12** anomalous terminations across two boots correlate with a reap, pid- and timestamp-locked —
|
|
82
|
+
including the sample that opened the issue (2026-07-30) and the original field report
|
|
83
|
+
(2026-08-16); receipts in `scripts/raw-acp-child-exit-measure/`. Two changes, both inside the
|
|
84
|
+
issue's repair fence (no timeout, no replay, no watcher/supervisor/hidden retry): (a) the default
|
|
85
|
+
launch is now an **entwurf-owned launcher** (`pi-extensions/lib/acp/claude-acp-launch.js`) that
|
|
86
|
+
imports the vendor **in-process** — same process, so there is no child to restart and it cannot
|
|
87
|
+
become a supervisor — carrying a name no vendor-name scanner matches, consuming no argv (the
|
|
88
|
+
vendor's own `argv.slice(1)` self-reinvocation still works), standing down if it would otherwise
|
|
89
|
+
be the only signal listener (an observer that suppressed default termination would make the
|
|
90
|
+
process signal-immune), and dying nonzero without retry if the import fails; (b) a caught
|
|
91
|
+
SIGTERM/SIGINT is recorded as a **typed lifecycle fact** on its own line
|
|
92
|
+
(`launch observed SIGTERM before child exit (sender not attributed)`) via an exact full-line
|
|
93
|
+
control frame that is consumed out of the vendor stderr tail — the tail stays vendor evidence,
|
|
94
|
+
the observation is entwurf's, and sender attribution is explicitly NOT claimed (that needs the
|
|
95
|
+
host journal). `CLAUDE_AGENT_ACP_COMMAND` stays verbatim: an operator who names their own command
|
|
96
|
+
owns the result. **Known trade:** after the name split a host janitor can no longer collect
|
|
97
|
+
entwurf's children even when they genuinely leak, so entwurf now owns that cleanup story.
|
|
98
|
+
**Read the order right: the cause was the host's janitor, and its owner has retired it**
|
|
99
|
+
(`nixos-config e283d92`, 2026-09-01 — `acp-zombie-reaper.timer` disabled). Measured there:
|
|
100
|
+
PR #245 is CLOSED, not merged; that deployment runs `acp.enabled=false` with no ACP agent;
|
|
101
|
+
acpx is not even installed in the running image (`/app/node_modules/acpx` absent, its `.bin`
|
|
102
|
+
entries dangling symlinks); and every reap since the 2026-06-10 ACP removal was a single-process
|
|
103
|
+
misfire matching our pid table. So the change here is **not what stops the symptom** — the
|
|
104
|
+
retirement is. It is defense-in-depth against the class, and that class is wider than this
|
|
105
|
+
issue: the selector reads the WHOLE `ps` line, so on a harness that puts the prompt in argv, a
|
|
106
|
+
session merely *discussing* `claude-agent-acp` matched. Measured 2026-09-01 with zero ACP
|
|
107
|
+
processes alive, the script's own counter read `alive_acp=3` — three ordinary agent sessions,
|
|
108
|
+
one of them the session investigating it. A launcher whose name we own survives the next such
|
|
109
|
+
janitor too. Gates:
|
|
110
|
+
new `check-acp-launch-namespace` (2 mutants) plus `check-acp-prompt-lifecycle` CELLs 12–13,
|
|
111
|
+
where 13 is the negative sibling holding that vendor prose mentioning `SIGTERM` can never forge
|
|
112
|
+
the observation (3 mutants). The primary repair still belongs to the janitor's owner — a cleaner
|
|
113
|
+
should scope by a positive marker it owns, not by a name anyone may share.
|
|
114
|
+
|
|
115
|
+
- **A vendor-written `config.yml` no longer reads as `unreadable`.** omp's own settings writer
|
|
116
|
+
emits `modelRoles:` followed by an indented `{}`, and `scripts/omp-tool-surface.py`'s
|
|
117
|
+
block-only reader returned None for the WHOLE file on that shape — so an untouched operator
|
|
118
|
+
config classified as unreadable and `doctor-omp-mcp` went RED for a reason unrelated to
|
|
119
|
+
`tools.xdev` (measured on a real host, omp 18.0.0). The reader now parses flow collections in
|
|
120
|
+
value position and as a whole child block. `check-omp-fresh-preflight` gains the vendor shapes
|
|
121
|
+
plus `[QK:OMP-XDEV-VENDOR-SHAPE-READABLE]` direct assertions — agreement between the two
|
|
122
|
+
readers could never catch this, since both collapse `unreadable` and `true` into "not false".
|
|
123
|
+
- **The Copilot plugin-row grammar admits the vendor's state token.** Copilot CLI 1.0.81 prints
|
|
124
|
+
`<qualified> (v0.1.0) (enabled)` plus an indented `from <path>` continuation line;
|
|
125
|
+
`copilot_exact_row_version` read the version as `0.1.0) (enabled`, called the row malformed,
|
|
126
|
+
and refused the birth install on a host whose plugin was installed and enabled — `entwurf
|
|
127
|
+
setup` reported `copilot-birth: FAIL`. The grammar now admits exactly one optional
|
|
128
|
+
`(enabled)`/`(disabled)` token; any other trailing token is still malformed. The fake vendors
|
|
129
|
+
in `scripts/fake-copilot-vendor.sh` and `check-copilot-birth-hook.ts` emit the 1.0.81 shape,
|
|
130
|
+
with `[QK:COPILOT-ROW-STATE-TOKEN-ADMITTED]` holding both directions.
|
|
131
|
+
|
|
132
|
+
## 0.16.0 - 2026-08-31
|
|
133
|
+
|
|
134
|
+
This release admits **OMP (`omp`) as the fifth garden backend** and closes the admission
|
|
135
|
+
contract that let a citizen ship without the legs that make it reachable. Bundles A, B and C
|
|
136
|
+
are one arc — birth and identity, addressed receive, visible fresh — and the durable half is
|
|
137
|
+
the general rule they forced: from OMP onward, the FIRST release of a harness admitted under
|
|
138
|
+
the #82 contract owes its clause 7 visible-fresh receipt as a release-gate MUST step, its
|
|
139
|
+
citizen↔fresh parity edge inside `pnpm run check:full`, and two cross-harness dispatch
|
|
140
|
+
receipts. Every OMP LIVE claim below is one Linux host, one model, one accepted run; that
|
|
141
|
+
limit is stated once in Notes and is not softened anywhere above it. (#87)
|
|
142
|
+
|
|
143
|
+
### Added
|
|
144
|
+
|
|
145
|
+
- **OMP is an addressable garden citizen.** `omp` enters the backend registry (`wakeMode`
|
|
146
|
+
`self-fetch`, `deliveryLevel` `D6`, `nativeIdLabel` `sessionId`) and
|
|
147
|
+
`pi-extensions/meta-bridge-omp.ts` mints it: an omp hook IS an in-process extension, so
|
|
148
|
+
birth, the scope fence, the status line and the sender marker are one module. Both birth
|
|
149
|
+
edges are bound — `session_switch` is where `/new`, fork and in-TUI resume re-fire — and
|
|
150
|
+
every mode but `mode === "tui"` is refused before any write. The fence is the vendor's own
|
|
151
|
+
mode and nothing else: `hasUI` is true under rpc/rpc-ui/ACP, so a fence built on it would
|
|
152
|
+
admit exactly the sessions this refuses. A task subagent mints nothing. The step-6 join is
|
|
153
|
+
one process, so the marker is keyed to `process.pid`, never `process.ppid`. Gates:
|
|
154
|
+
`check-omp-birth-hook`, `smoke-omp-bridge-state`, `scripts/mutants/omp-birth.json`. (#87)
|
|
155
|
+
- **An omp-native MCP hand that shadows the borrowed Claude import.** The writer targets omp's
|
|
156
|
+
own `<omp agent dir>/mcp.json` in the vendor's own writer shape, and the server key is a
|
|
157
|
+
PINNED LITERAL `entwurf-bridge` — that pin is the entire mechanism. On a host that ever used
|
|
158
|
+
Claude Code, omp already imports an `entwurf-bridge` server labeled
|
|
159
|
+
`external-mcp/claude-code`; native provider priority beats the import and dedupe is
|
|
160
|
+
first-wins on the key with `equivalent()` never consulted, so a byte-identical key suppresses
|
|
161
|
+
the import while a different key would load BOTH and one of them would keep introducing an
|
|
162
|
+
omp session as Claude Code. `disabledServers` is never the hide-import tool — suppression is
|
|
163
|
+
by name and a suppressed item still claims the key — so the writer refuses to install under a
|
|
164
|
+
denylist of its own key and the doctor is red while one exists. `doctor-omp-mcp` adds an
|
|
165
|
+
EFFECTIVE-source read (native-wins / import-wins / both-suppressed / no-entry) and labels it
|
|
166
|
+
what it is: a configuration read of vendor precedence, never a runtime receipt. Gate:
|
|
167
|
+
`smoke-omp-mcp-state`. (#87)
|
|
168
|
+
- **OMP receives addressed messages — the garden is no longer one-way for it.**
|
|
169
|
+
`pi-extensions/meta-bridge-receive-omp.ts` joins the citizen in the SAME process, holds an
|
|
170
|
+
`fs.watch` on its mailbox signal, and rings an announce-only doorbell through the vendor's
|
|
171
|
+
`pi.sendUserMessage` — measured to live on the factory object rather than the event ctx, and
|
|
172
|
+
measured to start a turn on an idle host with zero typing. The model drains with
|
|
173
|
+
`entwurf_inbox_read`, and that read is the receipt. The `/new` unarm is rail-specific: the
|
|
174
|
+
watch lives inside the operator's TUI, where pid plus start-key cannot see a citizen change
|
|
175
|
+
underneath a living process, so the old garden id is explicitly unarmed and the replacement
|
|
176
|
+
armed. Bounded arm defer, watch-error, vanished-signal and overlapping-edge paths are all
|
|
177
|
+
fail-closed. Install, uninstall and doctor surfaces ship with it, plus
|
|
178
|
+
`check-omp-receive-arm` with `scripts/mutants/omp-receive.json`, `smoke-omp-receive-state`
|
|
179
|
+
and `smoke-omp-receive-live`. (#87)
|
|
180
|
+
- **`entwurf_fresh_call` opens omp on all three public surfaces.** A five-axis pre-mutation
|
|
181
|
+
preflight decides the launch before the tmux window exists, so a missing prerequisite is a
|
|
182
|
+
named refusal instead of a dead window; the fifth axis is omp-specific (`tools.xdev !==
|
|
183
|
+
true`). There is NO positional prompt. The fixed registered flag `--entwurf-bootstrap`
|
|
184
|
+
carries a closed `{v,target,nonce,task}` grammar — an unknown key is a refusal — and the
|
|
185
|
+
installed birth extension runs a two-stage bootstrap: bounded readiness polling over both
|
|
186
|
+
public tool snapshots, a callback-ONLY prompt, then the task released only by the exact
|
|
187
|
+
successful `tool_result` (stored `toolCallId`, tool name, target, nonce and
|
|
188
|
+
`isError === false` all matching) and delivered at that same session's next `turn_end`. That
|
|
189
|
+
shape is a measurement, not a preference: the positional candidate opened its window, minted
|
|
190
|
+
its citizen, received the framing byte-identical, and answered the literal text `ACK` with
|
|
191
|
+
zero tool calls — the vendor's interactive UI defers MCP discovery while the positional
|
|
192
|
+
`initialMessage` prompts straight after `mode.init()`, so the turn began roughly 830ms before
|
|
193
|
+
the tool it was told to call existed. (#87)
|
|
194
|
+
- **`check-harness-admission-parity` — the missing edge between two closed loops.** Every
|
|
195
|
+
backend in `META_CITIZEN_BACKENDS` must appear in `FRESH_CALL_BACKENDS` or be a declared
|
|
196
|
+
pre-#82 legacy admission whose exception a reader can find in `DELIVERY.md`. Registry↔citizens
|
|
197
|
+
and surfaces↔fresh-set each already had a guard, but no file imported both constants, which is
|
|
198
|
+
how omp could pass the entire floor as a D6 citizen that `entwurf_fresh_call` cannot open. The
|
|
199
|
+
gate went red on `Unaccounted: omp` the moment it was added and green when Bundle C closed it.
|
|
200
|
+
It runs inside `check:contracts`, and therefore inside `pnpm run check:full`. (#87)
|
|
201
|
+
- **Two OMP LIVE steps in the release-gate MUST tier.** `smoke-omp-fresh-live` is clause 7's
|
|
202
|
+
worked instance. `smoke-omp-receive-live` reads the capability registry and decides its own
|
|
203
|
+
outcome — no drainable mailbox is a protocol SKIP, which `--cut` reads as red; a registry
|
|
204
|
+
claiming a receive rail with no acceptance body here is a FAIL. Neither is a hardcoded pass,
|
|
205
|
+
and the receive step was wired while omp was still outbound-only, so the one-way boundary
|
|
206
|
+
stopped being prose a cut could pass over in silence. (#87)
|
|
207
|
+
- **`docs/adding-a-harness.md` gains the shipped map and the release stop.** A comparative table
|
|
208
|
+
of the five admitted backends — lineage, receive rail, callback dialect, fresh launch form —
|
|
209
|
+
sits at the top so the variety is expected rather than re-derived at each admission. It pins
|
|
210
|
+
two lessons: lineage does not choose the rail (omp is pi underneath and rides Claude's mailbox
|
|
211
|
+
shape, because the rail follows the measured wake surface; what ancestry does instead is
|
|
212
|
+
concentrate the danger, since a shared env vocabulary is exactly where a fork splits a store),
|
|
213
|
+
and the doorbell doctrine — a hard bridge of measured dialects, explicit doorbells and honest
|
|
214
|
+
rejects is what makes the thing on the other side a peer rather than a disposable worker. The
|
|
215
|
+
release stop then states both executable halves of the admission rule plus the cross-harness
|
|
216
|
+
leg. (#87)
|
|
217
|
+
|
|
218
|
+
### Changed
|
|
219
|
+
|
|
220
|
+
- **`setup` is the install story on all three entry shapes.** npm global, npm project-local and
|
|
221
|
+
source clone now lead with `entwurf setup <project>`; `entwurf install <project>` is stated as
|
|
222
|
+
the narrower pi-wiring repair leaf that composes no harness. The 14-line native-harness paste
|
|
223
|
+
that read as the install recipe is now "repair and doctors" — one paragraph plus the command
|
|
224
|
+
names, with every per-unit installer, doctor and inverse retained, because a single broken unit
|
|
225
|
+
must still be redoable alone. The user-scope ownership matrix and the manual MCP registration
|
|
226
|
+
paths moved to the documents that already own them. Stale live claim corrected: after an
|
|
227
|
+
upgrade the operator was told to rerun every owned installer; `setup` re-composes them.
|
|
228
|
+
`package.json` gains the `copilot` keyword, shipped since 0.15.0 but unlisted. (#86)
|
|
229
|
+
- **OMP meta roots resolve as one indivisible bundle, never through `piAgentDir()`.** omp is a pi
|
|
230
|
+
fork and inherits pi's env vocabulary, so `PI_CODING_AGENT_DIR` means "pi's persistence root"
|
|
231
|
+
to entwurf and "my agent dir" to the vendor — a plain `omp --profile work` sets it. One pure
|
|
232
|
+
resolver leaf now serves both consumers, the in-process birth extension and the omp-labeled
|
|
233
|
+
bridge child, so agreement is by construction rather than two places computing the same thing.
|
|
234
|
+
A relative override fails closed instead of letting cwd become an authority: measured, the same
|
|
235
|
+
relative value resolved to two different stores because the extension's cwd is wherever the
|
|
236
|
+
operator launched omp while the doctor's is the repository. Installers refuse rather than guess
|
|
237
|
+
under an inherited `PI_CODING_AGENT_DIR` / `PI_CONFIG_DIR` / `PI_PROFILE`. (#87)
|
|
238
|
+
- **`PI_SESSION_ID` and `PI_AGENT_ID` are scrubbed at the launch seam for every backend.**
|
|
239
|
+
Measured on the operator host: a tmux server env carrying `PI_SESSION_ID` was inherited
|
|
240
|
+
verbatim by a new pane, so a sibling's bridge child could phone home under another citizen's
|
|
241
|
+
identity. The scrub is at the seam, not per backend. (#87)
|
|
242
|
+
- **The deterministic floor composes the omp gates.** `check:hermetic` gains
|
|
243
|
+
`smoke-omp-bridge-state`, `smoke-omp-mcp-state`, `smoke-omp-receive-state`,
|
|
244
|
+
`check-omp-receive-arm` and `check-omp-fresh-preflight`; `check:contracts` gains
|
|
245
|
+
`check-harness-admission-parity`. Both tiers still exclude the separately scheduled
|
|
246
|
+
`check-gate-qualification`, and `setup` still does not compose omp. (#87)
|
|
247
|
+
- **`docs/adding-a-harness.md` step 5 now says to measure the invocation FORM, not only the tool
|
|
248
|
+
name.** omp mounts MCP tools as `xd://` virtual devices by default (`tools.xdev`), so a correct
|
|
249
|
+
tool NAME is still not a callable function: the model must read the device for a schema that
|
|
250
|
+
`tools.xdevDocs` keeps off-prompt, then write JSON to the same path to execute. Measured on omp
|
|
251
|
+
18.0.0, a plain send under that default listed peers and then reported delivery with nothing
|
|
252
|
+
enqueued, and the mount also hid omp's own lsp, debug, browser and ast_edit — 11 devices in
|
|
253
|
+
all. `tools.xdev: false` restores every enabled tool top-level and leaves plan mode's
|
|
254
|
+
`xd://propose` finalization intact. (#87)
|
|
255
|
+
|
|
256
|
+
### Fixed
|
|
257
|
+
|
|
258
|
+
- **The bridge boot entry was in no typecheck program.** `mcp/tsconfig.json` extended the root
|
|
259
|
+
config without re-declaring `exclude`, so the inherited `"mcp"` resolved to `<repo>/mcp` and
|
|
260
|
+
filtered out everything its own `include` added; `mcp/entwurf-bridge/src/index.ts` — the
|
|
261
|
+
785-line bridge boot entry — was the only tracked `.ts` in the repo in no `tsc --noEmit`
|
|
262
|
+
program at all, and nothing imports it, so nothing rescued it through the import graph. Orphan
|
|
263
|
+
census 1 line before, 0 after; the mcp program's repo-file count moved 27 → 54, all product
|
|
264
|
+
sources. The emit path is untouched, so there is no product runtime change.
|
|
265
|
+
- **`entwurf_self` stopped rendering a mailbox nothing drains.** `metaDeliveryDomain` was derived
|
|
266
|
+
as native-push or self-fetch, so an omp citizen was handed a `mailboxPath` with no drainer. It
|
|
267
|
+
now has three values: `nativePushSupported` → native-push, else the decider's mailbox seam →
|
|
268
|
+
self-fetch, else none. Dispatch and `wakeMode` are untouched. (#87)
|
|
269
|
+
- **`doctor-omp-mcp` reads `tools.xdev` on the runtime axis.** An absent file or key applies the
|
|
270
|
+
vendor default (xdev on, empty inline allowlist) and is RED while the native hand is the
|
|
271
|
+
effective source; `xdev: false` is ok and a covering `xdevInlineDevices` glob is
|
|
272
|
+
ok-with-note. Ownership stays a separate question, and the smoke never touches the host
|
|
273
|
+
`config.yml`. (#87)
|
|
274
|
+
- **The bootstrap epoch now ends before the birth edge can bail.** Epoch termination depended on
|
|
275
|
+
reaching `startOmpBootstrap`, so a later birth edge that bailed early — a refused envelope or a
|
|
276
|
+
throwing upsert — skipped the invalidation, and on a same-id resume both handler fences still
|
|
277
|
+
passed, leaving the earlier defect shape alive in a narrow window. One rule, one owner:
|
|
278
|
+
`endBootstrapEpochOnLaterEdge` runs right after the mode fence, before the envelope is read,
|
|
279
|
+
and the consumed branch delegates to the same helper. Zero new state, zero new exports. (#87)
|
|
280
|
+
- **The omp-fresh qualification manifests were settled by measurement.** The first standalone
|
|
281
|
+
qualification run on the Bundle C bytes caught what static exactness could not: four mutants
|
|
282
|
+
whose claim and signature named different cells, one QK token minted twice in its gate source,
|
|
283
|
+
twelve find hunks left stale by the bundle's own refactor and the amendment's rewiring, and one
|
|
284
|
+
kill-site guess that died at an anonymous cell. Every repair was adjudicated by
|
|
285
|
+
apply/gate/revert measurement rather than by guess, and kill sites the floor disputed were
|
|
286
|
+
moved to where the kill actually lands. Separately, two mutants had been added to the
|
|
287
|
+
self-address lane without extending `EXPECTED_LANE_MUTANTS` — exactly the drift that assertion
|
|
288
|
+
exists to catch; the declared contract now says 5. (#87)
|
|
289
|
+
- **Two packaging omissions in the omp units.** `pi/meta-bridge-omp/entwurf-meta-omp/package.json`
|
|
290
|
+
and `pi/omp-receive/entwurf-receive-omp/package.json` were absent from `files[]`, so
|
|
291
|
+
`install-omp-receive` died in the installed package while passing from a checkout. (#87)
|
|
292
|
+
- **`check-pack-install` pins the transitive `@earendil-works/pi-telemetry` to 0.84.3.** Upstream
|
|
293
|
+
published the 0.84.4 family on 2026-08-28; `pi-agent-core@0.84.3` and `pi-ai@0.84.3` both carry
|
|
294
|
+
a `^0.84.3` caret on it, so the lockfile-less fresh-temp install floated to 0.84.4 and the leak
|
|
295
|
+
assertion failed closed in the `install-surface` CI job. The pin keeps the verified 0.84.3
|
|
296
|
+
constellation ours to hold; the leak assertion still guards every other pi package and any
|
|
297
|
+
future closure growth. The 0.84.4 bump itself remains a separate hard-cut lane.
|
|
298
|
+
- **The omp doctor treated Bundle C's empty tmux scrub as inherited identity.** `tmux -e NAME=`
|
|
299
|
+
writes `PI_SESSION_ID=` / `PI_AGENT_ID=` present-but-empty; authoritative readers trim and
|
|
300
|
+
require truthy values, so empty and absent are the same answer. The doctor was presence-testing
|
|
301
|
+
those names, which turned `check:full` red whenever a visible fresh omp citizen was alive.
|
|
302
|
+
It now flags only a nonblank value, and the hermetic smoke hands it fixture pids rather than
|
|
303
|
+
the host `pgrep`. (#87)
|
|
304
|
+
|
|
305
|
+
### Verification
|
|
306
|
+
|
|
307
|
+
Each receipt carries its own scope; none of them is transferable to another commit or host.
|
|
308
|
+
|
|
309
|
+
- **`./run.sh check-gate-qualification`** — **324/324 KILLED, NOT KILLED 0**, standalone on the
|
|
310
|
+
Bundle C candidate (`fd5e462`), independently re-verified by a second model on the gate
|
|
311
|
+
predicate plus a full-lane rescan and a 3/3 sample re-kill.
|
|
312
|
+
- **`pnpm run check:full`** — exit 0 in 430s on that same candidate, after the `build-bridge`
|
|
313
|
+
refresh the stale-dist tripwire demanded.
|
|
314
|
+
- **Clause 7 LIVE** — `smoke-omp-fresh-live` green 2026-08-30, 21 assertions, oracle / omp 18.0.0
|
|
315
|
+
/ `openai-codex/gpt-5.6-sol`. The sibling's garden `20260830T192913-df52b9` came from the
|
|
316
|
+
CALLBACK's sender envelope and never from the launch receipt; exactly one new citizen;
|
|
317
|
+
`lastEnqueuedAt 10:29:19.179Z` / `lastReadAt 10:29:24.673Z`, with the drain visible in that
|
|
318
|
+
session's own transcript for its own garden id. It took two runs: the first went red on
|
|
319
|
+
stage-two delivery alone, which is the argument for making it a MUST.
|
|
320
|
+
- **Receive acceptance (D6)** — 2026-08-30, oracle, omp 18.0.0: garden `20260830T140819-116f6a`,
|
|
321
|
+
`lastEnqueuedAt 05:08:20.555Z` / `lastReadAt 05:08:23.958Z`. D3 isolation is PROVEN, not
|
|
322
|
+
pending: with two live armed omp citizens, one addressed enqueue rang exactly one doorbell
|
|
323
|
+
while the sibling persisted no transcript and kept an empty mailbox.
|
|
324
|
+
- **Cross-harness leg** — 2026-08-31, the first bidirectional live-turn roundtrip on the committed
|
|
325
|
+
bytes: a claude-code citizen opened a fresh omp sibling through the public surface (callback
|
|
326
|
+
sender garden `20260831T124226-eac41a`), dispatched an addressed `entwurf_v2` into it, and the
|
|
327
|
+
omp citizen's own live turn drained the doorbell and replied into the claude mailbox.
|
|
328
|
+
- **`LIVE=1 ./run.sh release-gate <scratch> --cut`** — **MUST PASS=23 FAIL=0 SKIP=0,
|
|
329
|
+
BEHAVIOR PASS=1 FAIL=0 SKIP=0, `cut: OK`.** `check-gate-qualification` inside the gate
|
|
330
|
+
killed **325/325** mutants across 36 lanes. Log:
|
|
331
|
+
`/tmp/entwurf-release-gate-0.16.0.run2.DfMtRj/release-gate.log` (SHA-256
|
|
332
|
+
`2df4f6d4bddd563431ca41d2a43074f2cb6ccf9926ec6e8c7323de1a6ddf8192`).
|
|
333
|
+
A first attempt on the same versioned tree (scratch `.../entwurf-release-gate-0.16.0.AyHcIJ`)
|
|
334
|
+
hit one MUST FAIL in `smoke-entwurf-v2-matrix-live` C1b: the hidden-store resident did not
|
|
335
|
+
birth a record inside the 30s boot window. The same smoke rerun standalone passed 17 checks
|
|
336
|
+
in 4.9s; the rerun cut above is the acceptance. `pnpm run check:full` on the versioned tree
|
|
337
|
+
was exit 0 in 432s before P5.
|
|
338
|
+
|
|
339
|
+
### Notes
|
|
340
|
+
|
|
341
|
+
- **Evidence limit.** Every OMP LIVE claim above is one Linux host (oracle, ARM), one model, one
|
|
342
|
+
accepted run. Multi-host, multi-model and repeated fresh calls inside one process are not
|
|
343
|
+
claimed and are not evidenced here.
|
|
344
|
+
- **Operator prerequisite.** `tools: xdev: false` in `~/.omp/agent/config.yml`. Under the vendor
|
|
345
|
+
default the doorbell would name a tool the model cannot call, so both the fresh preflight and
|
|
346
|
+
the LIVE smokes check it as a precondition. `setup` does not compose omp.
|
|
347
|
+
- Measured against **omp 18.0.0** while the vendor announces 18.0.11. The `mode === "tui"`
|
|
348
|
+
discriminator, the `xd://` behaviour and the five measurement cells recorded in
|
|
349
|
+
`scripts/raw-omp-measure/README.md` §M7 are re-measurement targets on upgrade.
|
|
350
|
+
- Copilot's operator-metered clause 7 exception is preserved, not reopened. The release stop
|
|
351
|
+
applies from OMP onward, forward-only.
|
|
352
|
+
- The cross-harness leg's deterministic half — every post-contract citizen backend having a wired
|
|
353
|
+
cross-harness LIVE step or a declared metered exception — is an owed follow-up. Until that gate
|
|
354
|
+
lands the rule is prose, and `docs/adding-a-harness.md` says so in place.
|
|
355
|
+
- Pi `0.84.4` remains a separate hard-cut lane.
|
|
356
|
+
- #90 is measured but unfixed: installed Claude Code sends `model` as a STRING on the interactive
|
|
357
|
+
`SessionStart` envelope and omits it entirely in print mode, while the reader accepts only the
|
|
358
|
+
object shape, so claude-code records carry no model. Widening the reader and pinning both shapes
|
|
359
|
+
in a fixture is a separate lane.
|
|
360
|
+
|
|
7
361
|
## 0.15.1 — 2026-08-27
|
|
8
362
|
|
|
9
363
|
This patch is the Linux install-honesty floor for #86: Entwurf installs itself only,
|
package/DELIVERY.md
CHANGED
|
@@ -84,11 +84,12 @@ can be owned without being supported; a supported harness still has to walk
|
|
|
84
84
|
|---|---|---|---|
|
|
85
85
|
| **pi native Entwurf** | shipped | D7; D8 partial | Record-addressed Unix control socket. A record-less socket is diagnostic only and never dispatched. |
|
|
86
86
|
| **Claude Code interactive `>=2.1.217`** | shipped; Linux certified | D6; D7/D8 partial | Per-session mailbox + exec-form `FileChanged`/`asyncRewake`. B2 proved idle wake and same-session continuity on one NixOS host. |
|
|
87
|
-
| **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. |
|
|
87
|
+
| **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. Admitted before the #82 step 9 contract and not re-evaluated under it, so it is legacy citizen evidence, not a step-9 supported harness: `entwurf_fresh_call` cannot open an agy sibling, and nothing here should be read as claiming visible lifecycle parity. |
|
|
88
88
|
| **Codex app-server-backed TUI** | verified probe | D7; D8 unproven | WebSocket-over-UDS `turn/start` into a live `threadId`; status events expose completion. No owned native-citizen install/invocation lane. |
|
|
89
89
|
| **Codex embedded TUI** | deferred | D0 partial | No supported receive socket/hook on the measured standalone shape. |
|
|
90
90
|
| **Copilot CLI first-party extension** | raw transport probe; superseded by the owned product unit | D7 path observed; D3 control receipt incomplete; D8 unproven | CLI-spawned extension over stdio JSON-RPC; `joinSession()` + documented `fs.watch` → `session.send({mode:"enqueue"})`. Idle wake, exact-marker reply, and completion passed on 2026-08-23 (CLI 1.0.80, L4, one Linux host). Two-process isolation was observed but its decisive B log was not preserved. Kept as the transport receipt the owned receive unit was built on; the shipped unit differs deliberately — it announces the inbox instead of injecting the body. |
|
|
91
91
|
| **Copilot CLI garden citizen** | shipped in 0.15.0; send + receive + visible fresh accepted on one host | D6; D7 partial; D3 pending; D8 unproven | Birth, garden id, MCP hand and record-backed sender identity are accepted; the RECEIVER is an installed first-party extension that binds to the V3 record, writes a receiver marker owned by the WATCHER pid, and rings a doorbell the model drains with `entwurf_inbox_read`. `wakeMode` is `self-fetch`, so dispatch reaches the mailbox rail: armed → delivered, unarmed/stale → the honest `mailbox-undeliverable` refusal. **D6 is the owned-invocation LIVE acceptance of 2026-08-23** — garden `20260823T181316-d9f6ba`, native `20fe30c8-b2bc-4600-91a0-8a409131be51`, CLI 1.0.80: receive log `joined`→`armed`→`doorbell fresh=1`→`rang`, mailbox `lastEnqueuedAt 09:23:41.235Z` / `lastReadAt 09:23:56.480Z`, and a model reply on the same record/native/gid chain. **Visible fresh (step 9 clause 7) is a separate LIVE, 2026-08-25** — launch window `@89`/`%89` nonce `mux-fresh-call-690529ae99f99faa2252aefb`; exact-callback garden `20260825T085721-f68be0`; one `entwurf_v2` → `meta-mailbox → enqueued`; same garden `lastReadAt 2026-08-24T23:57:47.784Z` plus same-gid reply; GLG saw footer garden id and a healthy multi-turn window. Those rows stay unmerged. D7 is PARTIAL: reply and read receipt were observed, the completion taxonomy and long-haul operation were not. D3 (second-session isolation of an owned invocation) is PENDING — observed once, decisive log lost to scratch cleanup. Evidence level L4: one host. Launch through the owned invocation `entwurf copilot`, which sets `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` for that one process; `doctor-copilot-receive` reads live CLI environments because a session launched without it is silently inert. Visible fresh is operator-metered and is not a release-gate MUST. |
|
|
92
|
+
| **OMP (`omp`) garden citizen** | shipped in 0.16.0; send + receive + visible fresh accepted on one host | D6; D3 proven; D7 partial; D8 partial | Two in-process extensions in the operator's own TUI: birth mints the `mode === "tui"` host (subagents mint nothing) and names it as sender; the RECEIVER unit joins that citizen in the SAME process, holds an `fs.watch` on its mailbox signal, and rings an announce-only doorbell through the vendor's `pi.sendUserMessage` — measured to be on the FACTORY object, not the event ctx, and measured to start a turn on an idle host with zero typing (`agent_start` +31ms). `wakeMode` is `self-fetch`: the model drains with `entwurf_inbox_read` and THAT read is the receipt. **D6 is the LIVE acceptance of 2026-08-30** (oracle, omp 18.0.0) — garden `20260830T140819-116f6a`, `lastEnqueuedAt 05:08:20.555Z` / `lastReadAt 05:08:23.958Z`, and the citizen's own transcript carrying `mcp__entwurf_bridge_entwurf_inbox_read` for its own garden id. **D3 is PROVEN, not pending**: with two live omp citizens armed, one addressed enqueue rang exactly one doorbell and the sibling persisted no transcript and kept an empty mailbox. D7 is PARTIAL (`lastReadAt` needs no scraping; the reply does). D8 is PARTIAL — dedupe and every stale-handling path are implemented and hermetically pinned, ordering/loop-guard/crash-recovery are not. The `/new` unarm is the rail-specific one: the watch lives in the operator's TUI, so pid + start-key cannot see a citizen change underneath a living process, and without an explicit unarm the previous garden id would keep reading deliverable. Requires `tools: xdev: false` in `~/.omp/agent/config.yml` — the vendor default hides MCP tool schemas from the prompt, so the doorbell would name a tool the model cannot call. The decisive receipt lines — the ordering probe, the D6 chain, the D3 isolation and the `/new` unarm — are pasted into `scripts/raw-omp-measure/README.md` §M7 rather than left in a host-local `/tmp` path. Evidence level L4: one Linux host, ARM. **Visible fresh (step 9) is ACCEPTED — the clause 7 LIVE went green on 2026-08-30:** `entwurf_fresh_call` opens omp on all three public surfaces through the bare `omp` runtime with an explicit `--approval-mode yolo` width and the `mcp__entwurf_bridge_entwurf_v` callback name, behind a five-axis pre-mutation preflight whose fifth axis is omp-specific (`tools.xdev !== true`, without which the model cannot call the callback tool at all). **The first turn is a TWO-STAGE BOOTSTRAP rather than a positional prompt, and that is a measured correction, not a preference.** `[LIVE 2026-08-30]` the positional-prompt candidate opened its window and minted its citizen (garden `20260830T181342-452167`, native `01a051f2-3107-7147-8806-fa2a6f527610`), delivered the byte-identical framing as a user message at `09:13:42.413Z`, and the model answered the literal text `ACK` at `09:13:47.105Z` with ZERO tool calls; the caller timed out at 240s. `[source]` the interactive UI defers MCP discovery (`sdk.ts:1847-1855`, `:1881-1905`) while the positional `initialMessage` prompts straight after `mode.init()` (`main.ts:540-565`), and `[측정]` an observer on the same runtime saw `turn_start` at +654ms with the entwurf tools absent and the callback tool present only at +1484ms. So the launcher now carries `{v,target,nonce,task}` on the fixed registered flag `--entwurf-bootstrap`, and the in-process birth extension polls `getAllTools`(`source:"mcp"`) AND `getActiveTools` for the exact callback name, sends a callback-ONLY prompt, arms the task only on a `tool_result` whose stored `toolCallId`, tool name, target, nonce and `isError === false` all match, and DELIVERS it at the next `turn_end` of that same session. `[LIVE 2026-08-30]` that last boundary is itself a measured correction: a first attempt sent the task from inside the `tool_result` handler with an explicit `deliverAs: "followUp"`, the hook log showed the full chain (`bootstrap-armed` → `bootstrap-ready` +440ms → `bootstrap-callback-observed` → `bootstrap-released`), and the task still never appeared in the session — `[source]` an explicit `deliverAs` queues without starting a turn in either state, while the omitted form starts one when idle (`agent-session.ts:6511-6513`), which the same transcript confirmed three seconds later when the Bundle B doorbell's omitted-option send landed and started a turn. `[측정 2026-08-30]` the callback-only half is what was proven to work: model `openai-codex/gpt-5.6-sol`, tool live at +1105ms, prompt injected at +1107ms, and the sibling calling `mcp__entwurf_bridge_entwurf_v` with the exact nonce (`omp-cb-btkvva4r87` → `20260830T184054-1aa1f2`, `meta-mailbox → enqueued`). **The clause 7 acceptance, `smoke-omp-fresh-live` (release-gate MUST), 2026-08-30, 21 assertions, omp 18.0.0 / `openai-codex/gpt-5.6-sol`:** launch through `tools/call entwurf_fresh_call` with nonce `mux-fresh-call-34faea228f3c3638684b40ff`; sibling garden `20260830T192913-df52b9` taken from the CALLBACK's sender envelope and never from the launch receipt; exactly one new citizen (§3.5); addressed `entwurf_v2` → `meta-mailbox → enqueued`; `lastEnqueuedAt 10:29:19.179Z` / `lastReadAt 10:29:24.673Z`; the drain visible in that session's own transcript for its own garden id. **Both bootstrap stages are in that transcript in order** — the callback-only prompt at offset 970, the caller's task at 4732, no four-backend positional framing anywhere, and an assistant message after the task proving it started a turn rather than sitting in a queue. The unit's own log carries the state machine: `bootstrap-armed 10:29:13.399Z` → `bootstrap-ready 10:29:13.819Z` (+420ms) → `bootstrap-callback-observed 10:29:18.663Z` (`toolCallId=call_KZJtkxfzy1IEE4ejKutCPWcm|fc_0858…`) → `bootstrap-released 10:29:18.731Z` → `bootstrap-task-sent 10:29:18.759Z`. Evidence level L4: one Linux host, ARM, one run. `check-harness-admission-parity` keeps the deterministic half of the admission from being a matter of memory. What this does NOT establish: multi-host, multi-model, or repeated fresh calls in one process. **Cross-harness leg, 2026-08-31 (first bidirectional live-turn roundtrip on the committed bytes + operator redeploy):** a claude-code citizen (`20260831T090152-f998ac`) opened a fresh omp sibling through the public surface (nonce `mux-fresh-call-807cb693b1913ce98ffdbfd1`, callback sender garden `20260831T124226-eac41a`), dispatched an addressed `entwurf_v2` → `meta-mailbox → enqueued`, and the omp citizen's own live turn drained and replied into the claude mailbox — its self-report (doorbell → `entwurf_inbox_read`; callback-only first user message, task second) agrees with every receipt on the chain. |
|
|
92
93
|
| **Copilot CLI TUI+server** — *withdrawn lane, kept as evidence* | rejected | D7; D8 unproven | Older official-SDK probe over hidden `--ui-server`; idle enqueue worked, but loopback RPC authentication was not established. The bundled extension supersedes this candidate without reviving it. |
|
|
93
94
|
| **ACP Claude / Cortex** | shipped runtime, outside this matrix | — | ACP sessions are children launched by entwurf's pi adapter, not already-running native sessions to wake. |
|
|
94
95
|
|
|
@@ -137,7 +138,7 @@ native citizen or ACP backend. `turn/steer` is active-turn steering, not idle wa
|
|
|
137
138
|
|
|
138
139
|
### Copilot CLI: one citizen, two rails, one pending receipt
|
|
139
140
|
|
|
140
|
-
The
|
|
141
|
+
The shipped product owns the native citizen's birth, garden id, statusline, MCP hand,
|
|
141
142
|
outbound sender identity — and, since RAIL 5, the receiver. A real Copilot CLI 1.0.80
|
|
142
143
|
session minted a V3 record and sent under that record-backed garden id on 2026-08-21.
|
|
143
144
|
That proved who SENDS. Whether a reply LANDS is a different fact on a different process,
|