@junghanacs/entwurf 0.20.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +85 -190
- package/BASELINE.md +4 -3
- package/CHANGELOG.md +195 -14
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +202 -60
- package/README.md +49 -22
- package/VERIFY.md +37 -7
- package/docs/acp-backend-rail.md +0 -1
- package/docs/external-mcp-host.md +54 -33
- package/docs/setup-clean-host.md +110 -17
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +101 -109
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-fresh-preflight.js +326 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +22 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +6 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-native-push.js +30 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +7 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +20 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +227 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +50 -15
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +10 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/codex-ws-client.js +403 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/register.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-codex.js +325 -0
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +6 -1
- package/mcp/entwurf-bridge/src/index.ts +115 -111
- package/mcp/entwurf-bridge/tsconfig.build.json +1 -0
- package/package.json +13 -4
- package/pi-extensions/entwurf-control.ts +71 -19
- package/pi-extensions/lib/codex-fresh-preflight.ts +363 -0
- package/pi-extensions/lib/compaction-send-guard.ts +80 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +29 -3
- package/pi-extensions/lib/entwurf-peers-render.ts +4 -1
- package/pi-extensions/lib/entwurf-v2-contract.ts +6 -7
- package/pi-extensions/lib/entwurf-v2-native-push.ts +35 -18
- package/pi-extensions/lib/entwurf-v2-production.ts +10 -3
- package/pi-extensions/lib/entwurf-v2-surface.ts +7 -4
- package/pi-extensions/lib/meta-mailbox-body.ts +22 -13
- package/pi-extensions/lib/meta-sender-identity.ts +305 -0
- package/pi-extensions/lib/mux-fresh-call.ts +64 -19
- package/pi-extensions/lib/native-push/adapter.ts +21 -24
- package/pi-extensions/lib/native-push/codex-ws-client.ts +506 -0
- package/pi-extensions/lib/native-push/register.ts +7 -9
- package/pi-extensions/meta-bridge-hook-codex.ts +371 -0
- package/run.sh +218 -28
- package/scripts/check-agy-sender-identity.ts +1 -1
- package/scripts/check-codex-birth-hook.ts +264 -0
- package/scripts/check-codex-bridge-identity.ts +179 -0
- package/scripts/check-codex-native-push.ts +386 -0
- package/scripts/check-codex-sender-identity.ts +495 -0
- package/scripts/check-compaction-send-guard.ts +130 -0
- package/scripts/check-copilot-receive-arm.ts +4 -1
- package/scripts/check-entwurf-fact-provider.ts +38 -0
- package/scripts/check-entwurf-peers-surface.ts +13 -1
- package/scripts/check-entwurf-self-address.ts +15 -16
- package/scripts/check-entwurf-v2-contract.ts +4 -3
- package/scripts/check-entwurf-v2-decider.ts +7 -5
- package/scripts/check-entwurf-v2-native-push.ts +35 -7
- package/scripts/check-entwurf-v2-production.ts +203 -11
- package/scripts/check-entwurf-v2-runner.ts +1 -1
- package/scripts/check-entwurf-v2-surface.ts +1 -1
- package/scripts/check-gate-qualification.ts +6 -3
- package/scripts/check-harness-admission-parity.ts +0 -1
- package/scripts/check-mux-launch-tmux.ts +47 -2
- package/scripts/check-native-push-adapter.ts +20 -16
- package/scripts/check-native-push-register.ts +5 -1
- package/scripts/check-release-gate-outcomes.ts +47 -1
- package/scripts/check-setup-qualification.sh +3 -1
- package/scripts/codex-birth-doctor.sh +276 -0
- package/scripts/codex-birth-install.sh +414 -0
- package/scripts/codex-birth-uninstall.sh +170 -0
- package/scripts/codex-mcp-config.py +435 -0
- package/scripts/codex-statusline-config.py +434 -0
- package/scripts/codex_toml_io.py +532 -0
- package/scripts/lib/codex-fresh-live-protocol.ts +113 -0
- package/scripts/lib/codex-fresh-source-receipts.ts +399 -0
- package/scripts/lib/launch-receipt-windows.ts +46 -0
- package/scripts/lib/tmux-coordinate-row.ts +58 -0
- package/scripts/meta-bridge-fresh-cut.ts +6 -1
- package/scripts/mutants/codex-native.json +838 -0
- package/scripts/mutants/compaction-send-guard.json +103 -0
- package/scripts/mutants/entwurf-peers.json +19 -0
- package/scripts/mutants/mux-fresh-call.json +19 -8
- package/scripts/mutants/omp-fresh.json +6 -4
- package/scripts/mutants/release-gate.json +13 -0
- package/scripts/mutants/v2-surface.json +53 -1
- package/scripts/raw-async-delivery/README.md +2 -1
- package/scripts/raw-codex-measure/README.md +114 -46
- package/scripts/smoke-agy-native-push-live.ts +3 -1
- package/scripts/smoke-codex-birth.sh +347 -0
- package/scripts/smoke-codex-config-state.sh +511 -0
- package/scripts/smoke-codex-fresh-live.ts +1186 -0
- package/scripts/smoke-codex-native-push-live.ts +75 -0
- package/scripts/smoke-setup-verdict.sh +123 -10
- package/scripts/tsconfig.json +1 -0
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,189 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.21.0 - 2026-09-13
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **This is a minor release because Codex support adds a new visible citizen axis, not merely a
|
|
12
|
+
patch to an existing rail.** The operator-owned exact `codex` tmux home gives the app-server and
|
|
13
|
+
supported Codex TUIs a stable visible place without making Entwurf their lifecycle manager. UX
|
|
14
|
+
symmetry means each backend remains a sibling with its own transcript, auth, native tools, and
|
|
15
|
+
visible seat—not that unlike transports are relabeled as identical. The release also carries the
|
|
16
|
+
independent #111 and #112 bug repairs.
|
|
17
|
+
- **OpenAI Codex CLI becomes an app-server-backed native-push citizen (#95).**
|
|
18
|
+
A user-scope `SessionStart` hook, declared in the operator's own `$CODEX_HOME/hooks.json`,
|
|
19
|
+
mints the V3 record on the first turn and sets the visible thread title. It needs no root:
|
|
20
|
+
the installer refuses to run as uid 0, and the declaration is trust-gated rather than
|
|
21
|
+
prompt-free — the operator answers the vendor's prompt with "Trust all" ONCE in their own
|
|
22
|
+
visible Codex, and the vendor records that decision itself. Entwurf never computes, writes,
|
|
23
|
+
pre-seeds or reads a `trusted_hash`, and never touches `config.toml`. Because the vendor
|
|
24
|
+
hashes the declaration identity (event, matcher, handler path) and not the launcher's
|
|
25
|
+
contents, the payload closure can be upgraded on later releases without asking again. The bridge strictly joins each request's Codex metadata to
|
|
26
|
+
that record, so multiple visible TUIs may share one app-server without sharing a
|
|
27
|
+
process marker. The purpose is to preserve Codex's native tools, delegation, and work
|
|
28
|
+
context as a citizen — not to add an ACP Codex backend or duplicate GPT access.
|
|
29
|
+
- **Codex gets three independently owned install/doctor/inverse atoms.**
|
|
30
|
+
`install-codex-birth` owns only the fixed `$CODEX_HOME/hooks.json` declaration plus its
|
|
31
|
+
launcher/payload closure under `${XDG_DATA_HOME:-~/.local/share}/entwurf/codex-birth`, with a
|
|
32
|
+
digest inventory that licenses an exact inverse and refuses drifted bytes;
|
|
33
|
+
`install-codex-mcp` owns only `[mcp_servers.entwurf-bridge]`; and
|
|
34
|
+
`install-codex-statusline` owns only `thread-title`. The MCP atom also owns the exact
|
|
35
|
+
`env_vars` names that forward `CODEX_HOME`, Entwurf garden/control roots, and the
|
|
36
|
+
operator-owned app-server's `TMUX`/`TMUX_PANE`. `setup` never escalates or starts it.
|
|
37
|
+
- **`entwurf_fresh_call` accepts `backend: "codex"` on both public tool surfaces and the
|
|
38
|
+
operator skill.** It requires an explicit model and uses the measured
|
|
39
|
+
`codex --remote unix://<default-socket> --model … --dangerously-bypass-approvals-and-sandbox`
|
|
40
|
+
shape. The birth unit, MCP/env boundary, visible title, and the operator-owned app-server
|
|
41
|
+
socket are checked before tmux mutation. With placement omitted, Codex resolves the exact
|
|
42
|
+
existing `codex` tmux home; a missing home rejects without creating one. Explicit placement
|
|
43
|
+
remains an expert override. This does not infer an attached TUI seat from request identity.
|
|
44
|
+
- **Omitted placement becomes a backend-selected policy, and Codex is its first implementation.**
|
|
45
|
+
Every backend could already be sent to an operator-owned existing seat through explicit
|
|
46
|
+
`placement.tmuxSession`; that is unchanged, and named `claude`/`pi` seats stay available that
|
|
47
|
+
way without becoming omitted-placement defaults. What is new is that omitting placement no
|
|
48
|
+
longer means one thing for every backend: `pi`, `claude-code`, `copilot` and `omp` still open
|
|
49
|
+
in the caller's seat, while `codex` resolves its exact operator-owned home. tmux remains the
|
|
50
|
+
visible launch seat, never an address — the garden id is the address and arrives in the
|
|
51
|
+
callback envelope. Sibling symmetry is transcript, auth, native tools and visibility; it is
|
|
52
|
+
not a claim that the transports are the same.
|
|
53
|
+
- **Why a client-side home rather than a vendor seat carrier.** Upstream
|
|
54
|
+
[openai/codex#44774](https://github.com/openai/codex/issues/44774) records the maintainer's
|
|
55
|
+
preference for client-side terminal/window management, citing multi-client steer semantics and
|
|
56
|
+
network propagation. Rather than wait for a request→pane carrier or guess one, 0.21.0 takes the
|
|
57
|
+
client-side route the exact `rust-v0.153.4` source supports: an operator-owned exact home plus
|
|
58
|
+
explicit placement, with the wider attached-TUI topology left unsupported and unclaimed.
|
|
59
|
+
|
|
60
|
+
### Changed
|
|
61
|
+
|
|
62
|
+
- **The native-push rail is adapter-specific instead of Antigravity-shaped.** Codex liveness
|
|
63
|
+
is `thread/loaded/list` over the app-server WebSocket UDS; delivery is the measured one-shot
|
|
64
|
+
`codex queue --remote … --thread … --message …`. It has no mailbox, receiver marker, or
|
|
65
|
+
resume surface. Unlike Antigravity, Codex delivery is never retried because vendor acceptance
|
|
66
|
+
may precede the CLI receipt; replay would duplicate the user's message.
|
|
67
|
+
- **Codex remains outside ACP and Entwurf remains outside Codex lifecycle ownership.**
|
|
68
|
+
Entwurf does not install Codex, supply auth, expose a generic app-server API/manager, or
|
|
69
|
+
start/supervise/restart the app-server or create its tmux home. The supported topology is
|
|
70
|
+
one operator-owned existing session named `codex` containing the app-server and supported
|
|
71
|
+
Codex TUIs. N arbitrary attached TUIs across sessions still have no request→TUI seat join;
|
|
72
|
+
that wider topology is unsupported and unclaimed rather than a blocker to the explicit home.
|
|
73
|
+
- **`entwurf_peers` bounds expensive historical observation to its 32 rendered rows (#112).**
|
|
74
|
+
Full-store parsing, duplicate/conflict authority, socket liveness, diagnostics, and all 1,012
|
|
75
|
+
measured payload rows remain intact; older receiver/transcript cells say `unobserved` rather
|
|
76
|
+
than fabricating facts. On the 1,012-record fixture, repeated warm composition fell from about
|
|
77
|
+
3.2s to 70–103ms. Generic fact-provider callers remain unbounded unless they explicitly opt in.
|
|
78
|
+
- **Version-coherence gates no longer require concise `AGENTS.md` to duplicate package pins.**
|
|
79
|
+
The owning runtime/package documents remain checked; removing redundant pin prose from the
|
|
80
|
+
maintainer guide no longer makes an otherwise coherent floor fail.
|
|
81
|
+
|
|
82
|
+
### Upgrade note
|
|
83
|
+
|
|
84
|
+
Codex native delivery requires three user-scope atoms and one operator trust answer. No step
|
|
85
|
+
needs root:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
entwurf install-codex-birth
|
|
89
|
+
entwurf install-codex-mcp
|
|
90
|
+
entwurf install-codex-statusline
|
|
91
|
+
|
|
92
|
+
# Then, ONCE, in a visible plain Codex: answer the hook prompt with "Trust all and continue"
|
|
93
|
+
# and send one first turn. Until the vendor records that receipt the hook is declared and
|
|
94
|
+
# never runs, and `doctor-codex-birth` / `setup` stay non-green and say so.
|
|
95
|
+
|
|
96
|
+
# First create/open the operator-owned tmux session named exactly `codex`.
|
|
97
|
+
# From a pane in that session:
|
|
98
|
+
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
99
|
+
mkdir -p "$CODEX_HOME/app-server-control"
|
|
100
|
+
codex app-server --listen "unix://$CODEX_HOME/app-server-control/app-server-control.sock"
|
|
101
|
+
# Seat supported Codex TUIs in this same `codex` session.
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Then restart/open Codex and send its first turn. `entwurf setup <project>` never runs sudo and
|
|
105
|
+
never starts the app-server.
|
|
106
|
+
|
|
107
|
+
### Verification
|
|
108
|
+
|
|
109
|
+
- The GPT-6 review reopened five surfaces in the candidate: terminal parser, explicit
|
|
110
|
+
env-name boundary, setup acceptance, fresh preflight safety, and clause-7 composition.
|
|
111
|
+
The prior “source-complete; only host ownership remains” wording is withdrawn.
|
|
112
|
+
- The 2026-09-11 Codex CLI 0.153.4 run remains pre-amendment evidence: native-push and a
|
|
113
|
+
public MCP call woke one visible loaded thread; authenticated request identity resolved
|
|
114
|
+
`agentId=meta-session/codex`, `replyable=true`; and a source hook minted a record in an
|
|
115
|
+
isolated store. It does not qualify the amended candidate.
|
|
116
|
+
- The 2026-09-12 Codex 0.153.4 explicit-home LIVE passed 57 assertions. A real initial Pi
|
|
117
|
+
ran at `$150/@397`; the operator app-server remained at `$158/@390/%390`; omitted-placement
|
|
118
|
+
Codex opened at `$158/@398`; and Codex opened outbound Pi at `$158/@399`. Exact callbacks
|
|
119
|
+
and addressed delivery succeeded both ways. `DELIVERY.md` carries the garden ids, thread,
|
|
120
|
+
nonces, preserved log path, and SHA-256.
|
|
121
|
+
- Two red attempts repaired the acceptance itself. “Wait” had let Codex call one-hour
|
|
122
|
+
`wait_agent`; the task now ends its turn and forbids wait tools. A model also reformatted
|
|
123
|
+
a copied LAUNCH receipt; the gate compares source-owned tool results rather than treating that prose
|
|
124
|
+
as raw evidence. Failure cleanup interrupts only the exact smoke-owned active Codex turn and removes
|
|
125
|
+
only source-receipt-named windows.
|
|
126
|
+
- The second full prepare P5 remained honestly red at **MUST 23 PASS / 1 FAIL / 0 SKIP**. The initial
|
|
127
|
+
Pi's source transcript proved Codex launch, exact callback, native-push delivery, outbound Pi launch
|
|
128
|
+
and callback, and Codex's final mailbox enqueue; it also showed the missing observation's direct
|
|
129
|
+
cause: the model shortened expected launch-report token `…1G5XEKQH` to `…1G5XEKQ`. Enqueue did not
|
|
130
|
+
prove the fixture read, and cleanup had removed the mailbox needed to distinguish every downstream
|
|
131
|
+
observer hypothesis. The amendment removes intermediate model coordinate reports entirely: Pi JSONL
|
|
132
|
+
call/result rows are joined by call id, exact tool name/arguments, non-error result, and uniqueness;
|
|
133
|
+
Codex uses the corresponding structured app-server MCP items; raw callback events supply garden ids.
|
|
134
|
+
Mailbox prose can never authorize a window kill. Every drain now persists filename, byte length,
|
|
135
|
+
SHA-256, observed token candidates, phase-specific selection/exclusion reason and a 0600 body artifact
|
|
136
|
+
immediately, plus resolved-root/run/source-path manifest and a mandatory fixture/record/transcript/thread
|
|
137
|
+
snapshot before destructive cleanup on every outcome. That snapshot uses the record owner's `.meta.json`
|
|
138
|
+
filename, records missing expected sources, and still copies known raw files when optional identity recovery
|
|
139
|
+
throws; final acceptance also requires known `completed` Codex turn/items state and logs payload validation
|
|
140
|
+
separately from token/sender candidate selection. The preserved failed-rollout extraction
|
|
141
|
+
(`c3a28938…`) confirms raw outbound launch → callback → final enqueue but still not fixture read; its tracked
|
|
142
|
+
positive fixture is explicitly labelled a vendor-source-derived v2 projection, not a captured `thread/read`
|
|
143
|
+
response. A second defect the amendment itself introduced was then measured and closed: the smoke read the
|
|
144
|
+
initial Pi's `transcriptPath` once at callback correlation, and a record that gained that path 34s later
|
|
145
|
+
left every subsequent source observation permanently empty — one 300s red whose chain had in fact run to
|
|
146
|
+
completion, proven by the Codex thread's own completed final `entwurf_v2` result. The resolution is a pure
|
|
147
|
+
leaf that re-reads the record while its cached path is empty (an unreadable record stays fail-loud; only
|
|
148
|
+
"no path yet" is pending), its own `CODEX-LIVE-SOURCE-PATH-RE-RESOLVED` claim and mutant, and an explicit
|
|
149
|
+
`no unverified child window killed` line so a run that never obtains source evidence names its
|
|
150
|
+
unrecoverable windows instead of leaking them. Declared inventory is now 475 mutants across 43 lanes.
|
|
151
|
+
The amended standalone LIVE then passed: **48 assertions, exit 0**, final source audit `initial-pi=3/3`
|
|
152
|
+
and `codex=3/3` completed exact, all three opened windows reclaimed by their own receipts, artifact
|
|
153
|
+
`.probe-artifacts/codex-fresh-live-fZccoK/`. Assertion count is not comparable with the pre-amendment 57:
|
|
154
|
+
that contract counted model coordinate reports this one removes.
|
|
155
|
+
- **Release acceptance for this candidate: `check:full` exit 0 in 502s, then the LIVE release gate
|
|
156
|
+
`--cut` at MUST PASS=24 FAIL=0 SKIP=0, BEHAVIOR PASS=1 FAIL=0 SKIP=0, `cut: OK`.** Its
|
|
157
|
+
`check-gate-qualification` MUST step killed 475/475 across 43 lanes with the origin HEAD and
|
|
158
|
+
work-surface hash identical before and after. The aggregate's own Codex leg repeated the
|
|
159
|
+
48-assertion source-owned acceptance (artifact `.probe-artifacts/codex-fresh-live-2oId4C/`), and the
|
|
160
|
+
mux lifecycle MUST passed in the same run. Scratch log sha256 `942d5fa0…`.
|
|
161
|
+
- **Observation, not a repaired defect.** The first acceptance attempt at the identical source
|
|
162
|
+
fingerprint failed two model-in-loop MUST steps: a callback nonce arrived one character short
|
|
163
|
+
(`…c70cfb` for `…c70cfb2`) and an addressed instruction carried the wrong payload. Both oracles
|
|
164
|
+
refused fail-closed and named their cause, and the joined source receipts proved delivery and rails
|
|
165
|
+
were correct, so nothing in the product was changed. The same candidate, model, and environment then
|
|
166
|
+
passed. That leaves an intermittent exact-byte transfer failure in the model lane as a recorded
|
|
167
|
+
observation; the retry does not establish a cause for it.
|
|
168
|
+
- The first 460-mutant qualification honestly stopped at 454/460. One wait-task mutant was
|
|
169
|
+
stale after the prompt repair; the birth safe-umask mutant was killed earlier by the new
|
|
170
|
+
package-root mode doctor but carried the wrong assertion label; and four setup claims shared
|
|
171
|
+
one control-red because `smoke-setup-verdict` ran real pnpm inside the qualifier's
|
|
172
|
+
node_modules-symlink snapshot. The manifest was re-pinned, safe-umask attribution now has one
|
|
173
|
+
QK helper at both valid failure leaves, and the setup behavior gate uses a strict fixture
|
|
174
|
+
pnpm accepting only a no-op `install --frozen-lockfile` or the source-owned `build-bridge`
|
|
175
|
+
emit, whose snapshot-local dist is removed on exit. The next run killed all 460 mutants but
|
|
176
|
+
correctly rejected its own impure snapshot: the fixture had called the production dist-lock
|
|
177
|
+
wrapper, which removed its lock but left the ignored `.tmp-verify` parent. The fixture now
|
|
178
|
+
invokes the process-exclusive snapshot emit directly; a focused pre/post tree-manifest replay
|
|
179
|
+
was byte-identical. The fresh run then killed **460/460** mutants across 43 lanes in 53m42s
|
|
180
|
+
with the origin and snapshot surfaces pure. Biome only collapsed the new manifest arrays onto
|
|
181
|
+
one line afterward (claim/subject/find/replace bytes and semantics unchanged), and the frozen
|
|
182
|
+
full floor passed in 506s. The receipt-bearing final candidate passed the full floor again
|
|
183
|
+
in 501s before the implementation commit and local-main merge.
|
|
184
|
+
|
|
185
|
+
### Fixed
|
|
186
|
+
|
|
187
|
+
- **The Copilot receiver parent-death mutant no longer leaves one PID-1 fixture child per qualification run.** P9 found ten reparented Node stubs from ten qualifications. The gate did detect the mutant, but its failing assertion threw before the cleanup statement below it; cleanup now kills the surviving mutant child before asserting, preserving the same attributed red while leaving no process behind.
|
|
188
|
+
- **Control-socket send during Pi compaction is no longer a false `delivered:true` (#111).** A compacting Pi citizen is neither idle nor an ordinary streaming turn, but the receiver only sampled `ctx.isIdle()` and forwarded every non-idle send into `pi.sendMessage({ triggerTurn: true })`. Installed Pi 0.85.1 `sendCustomMessage` then starts `_runAgentPrompt` when not streaming — racing `compact()`'s session rewrite, which is the field path that can make compaction "풀린다". There is no public `ExtensionContext.isCompacting()`. The resident arms on `session_before_compact` and refuses as `compacting`; quiet unknown non-idle (`!idle && ctx.signal === undefined`) is fail-closed as `busy`, not `compacting`, because `ctx.signal` is `agent.activeRun?.abortController.signal` and is already gone during `_handlePostAgentRun` retry/continuation while `_isAgentRunActive` is still true — that cell also covers the manual-compact start race and branch summary, which the public API cannot tell apart. Either token: no `pi.sendMessage`, no `delivered:true`. Idle and live-run steer/followUp are unchanged. Frozen v2 reject taxonomy is untouched — this is an in-band RPC refusal.
|
|
189
|
+
|
|
7
190
|
## 0.20.1 - 2026-09-10
|
|
8
191
|
|
|
9
192
|
### Fixed
|
|
@@ -124,17 +307,15 @@ Hosts with no detected harness, and every Linux host, see no new prompt.
|
|
|
124
307
|
by the promotion above; it is where a borrowed Mac produces the physical-host
|
|
125
308
|
evidence the CI runner cannot.
|
|
126
309
|
- **`scripts/raw-codex-measure/` — Codex 0.153.4 vendor measurement (#95 step 1).**
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
`PIN_CODEX_MINOR` 0.144 → 0.153 is a re-verification of the archived drift
|
|
137
|
-
probe, not a product pin.
|
|
310
|
+
**At the measurement landing on 2026-09-08**, no Entwurf Codex unit had been
|
|
311
|
+
installed or built, no product record/doctor existed, and fresh did not include
|
|
312
|
+
Codex. Those are dated step-1 facts, not the current candidate state. The ledger
|
|
313
|
+
established first-turn `SessionStart`, callback spelling
|
|
314
|
+
`mcp__entwurf_bridge__entwurf_v2`, the shared-app-server refutation of a pid-keyed
|
|
315
|
+
citizen join, root-owned prompt-free hooks, and `thread/name/set`. Later #95 work
|
|
316
|
+
added the record/native-push/fresh candidate described under Unreleased.
|
|
317
|
+
`PIN_CODEX_MINOR` 0.144 → 0.153 was a re-verification of the archived drift probe,
|
|
318
|
+
not a product pin.
|
|
138
319
|
|
|
139
320
|
### Changed
|
|
140
321
|
|
|
@@ -261,9 +442,9 @@ Lane receipts (oracle, 2026-09-09) plus prepare P4/P5 on this host. There is
|
|
|
261
442
|
CommandLineTools stub. Both are cells the borrowed-Mac probe
|
|
262
443
|
(`scripts/raw-macos-measure/probe.sh`, M6 and M3) is built to answer. Do
|
|
263
444
|
not fill them from a CI image spec.
|
|
264
|
-
- **Codex
|
|
265
|
-
|
|
266
|
-
|
|
445
|
+
- **On the 0.20.0 release date (2026-09-09), Codex was not a garden backend in that
|
|
446
|
+
cut.** Step 1 of #95 was measurement only and `entwurf_fresh_call` did not include
|
|
447
|
+
Codex. This is release archaeology; 0.21.0 support supersedes it.
|
|
267
448
|
|
|
268
449
|
## 0.19.0 - 2026-09-07
|
|
269
450
|
|
package/CONTRIBUTING.md
CHANGED
|
@@ -4,7 +4,7 @@ This is a daily-driver bridge. Correctness beats feature breadth. Read this befo
|
|
|
4
4
|
|
|
5
5
|
## What this repo is
|
|
6
6
|
|
|
7
|
-
`entwurf` is a **garden-citizen dispatch bridge** — entwurf-core (v2 dispatch) + a meta-bridge + a pi adapter + an **ACP plugin on a two-backend adapter rail** — that lets already-running harnesses address one another by garden id; pi is one adapter, not the subject. The ACP plugin borrows the backend's identity (system prompt preset, model behavior, tool implementations) and shapes the *operating surface* — tools, MCP, skills, permissions — to match pi's own policy **wherever that backend exposes a knob for it**. Where it does not, the plugin does not fake one: a cortex session keeps its own native tool surface and receives MCP through an overlay projection, so "shaped to pi's policy" is a Claude-strength claim, not a universal one. Claude is the reference ACP backend and Snowflake Cortex Code is the second (landed 0.13.0, `cortex-` prefixed ids — [docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)); Codex
|
|
7
|
+
`entwurf` is a **garden-citizen dispatch bridge** — entwurf-core (v2 dispatch) + a meta-bridge + a pi adapter + an **ACP plugin on a two-backend adapter rail** — that lets already-running harnesses address one another by garden id; pi is one adapter, not the subject. The ACP plugin borrows the backend's identity (system prompt preset, model behavior, tool implementations) and shapes the *operating surface* — tools, MCP, skills, permissions — to match pi's own policy **wherever that backend exposes a knob for it**. Where it does not, the plugin does not fake one: a cortex session keeps its own native tool surface and receives MCP through an overlay projection, so "shaped to pi's policy" is a Claude-strength claim, not a universal one. Claude is the reference ACP backend and Snowflake Cortex Code is the second (landed 0.13.0, `cortex-` prefixed ids — [docs/acp-backend-rail.md](./docs/acp-backend-rail.md#cortex-code-audit-d1d10)); Codex is not on this rail at all — it is an unreleased native-push candidate with record birth and delivery-probe evidence (see AGENTS.md, DELIVERY.md), never ACP-managed — and Gemini is not a shipped backend. That is the entire ACP-rail scope.
|
|
8
8
|
|
|
9
9
|
**How a backend joins the rail** (the shape a PR must take): one adapter object in `pi-extensions/lib/acp/backend-adapter.ts` + its own curated rows/overlay modules + its own `check-acp-*` gate and mutant lane. Backend-specific *behavior* must stay behind the adapter, and backend-specific settings ride the opaque `adapterSettings` seam rather than growing the common config. That is not a ban on ever touching the common layer (`backend.ts`'s turn loop, `acp-client.ts`, `event-mapper.ts`, `session-store.ts`, `config.ts`) — cortex's landing did change `backend.ts` to pass the authoritative session key through the generic `ensureOverlay` seam. The rule is narrower and stricter: a common-layer change must be **backend-invariant** (it reads no backend name and branches on no backend) and **separately gated**. A common file that grows an `if (backend === …)` is the thing to reject.
|
|
10
10
|
|
package/DELIVERY.md
CHANGED
|
@@ -88,8 +88,8 @@ physical host. Do not read a D-level cell as a Darwin receipt.
|
|
|
88
88
|
| **pi native Entwurf** | shipped | D7; D8 partial | Record-addressed Unix control socket. A record-less socket is diagnostic only and never dispatched. |
|
|
89
89
|
| **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. |
|
|
90
90
|
| **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. |
|
|
91
|
-
| **Codex app-server
|
|
92
|
-
| **Codex embedded TUI** | deferred | D0 partial |
|
|
91
|
+
| **Codex CLI app-server citizen** | supported in 0.21.0; explicit-home acceptance green on Linux at 0.153.4 | D6 accepted; D7 partial; D8 unproven | Vendor-trusted user-scope `SessionStart` birth plus strict per-request metadata join; no shared-pid sender marker. `thread/loaded/list` probes the operator-owned app-server UDS and one-shot `codex queue` delivers with no retry. The supported visible topology is one operator-owned existing tmux session named `codex`: the app-server and supported Codex TUIs sit there, omitted Codex fresh placement selects it, and Codex-opened Pi stays beside its caller. Missing home rejects; Entwurf creates/supervises none of it. Exact 0.153.4 source bounds unrestricted attached-TUI placement as unsupported, not as a blocker to this explicit topology. |
|
|
92
|
+
| **Codex embedded TUI** | deferred | D0 partial | At the 2026-09-08 Codex 0.153.4 measurement, standalone mode had no `watchPaths`/`FileChanged`/`asyncRewake` analogue or supported idle receive route. This is dated vendor evidence, not a claim that the current candidate lacks records or fresh. |
|
|
93
93
|
| **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. |
|
|
94
94
|
| **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. |
|
|
95
95
|
| **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. |
|
|
@@ -130,64 +130,206 @@ the pid/start-key sender marker would be last-writer-wins. Current operator chec
|
|
|
130
130
|
in [BASELINE.md](./BASELINE.md); deterministic ownership and sender gates run in
|
|
131
131
|
`pnpm run check:full`.
|
|
132
132
|
|
|
133
|
-
### Codex:
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
133
|
+
### Codex: one app-server-backed native-push shape
|
|
134
|
+
|
|
135
|
+
Codex support is deliberately narrower than “drive Codex” and ships that way in
|
|
136
|
+
**0.21.0**. Its purpose is to keep the operator's real Codex session —
|
|
137
|
+
native tools, delegation, auth, transcript, and work context — addressable through
|
|
138
|
+
the app-server-backed shape measured at Codex CLI **0.153.4**. It is not ACP and does
|
|
139
|
+
not duplicate GPT access:
|
|
140
|
+
|
|
141
|
+
```text
|
|
142
|
+
operator starts app-server in existing exact tmux session `codex`
|
|
143
|
+
→ its configured MCP env_vars forward that home coordinate and explicit roots
|
|
144
|
+
→ visible codex TUI attaches with --remote unix://<default socket>
|
|
145
|
+
→ first turn runs the vendor-trusted user-scope SessionStart birth
|
|
146
|
+
→ V3 record(nativeSessionId = threadId)
|
|
147
|
+
→ thread/name/set(gardenId)
|
|
148
|
+
→ MCP tools/call carries strict request metadata
|
|
149
|
+
→ entwurf_self / entwurf_v2 resolve that exact record
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The standalone embedded TUI remains outside this rail: the 2026-09-08 measurement
|
|
153
|
+
found no idle receive route equivalent to the app-server. `turn/steer` is active-turn
|
|
154
|
+
steering, not idle wake. Entwurf does not start, stop, supervise, or health-loop the
|
|
155
|
+
app-server. The operator starts it **inside the existing exact tmux session `codex`**:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
# Run from a pane in the operator-owned tmux session named exactly `codex`.
|
|
159
|
+
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
160
|
+
mkdir -p "$CODEX_HOME/app-server-control"
|
|
161
|
+
codex app-server --listen "unix://$CODEX_HOME/app-server-control/app-server-control.sock"
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
This session is the supported home for the app-server and Codex TUIs. Omitted Codex
|
|
165
|
+
fresh placement resolves its exact name from the caller's tmux server; Codex's MCP child
|
|
166
|
+
then inherits the app-server's own `TMUX`/`TMUX_PANE`, so omitted outbound Pi placement
|
|
167
|
+
stays in the home. An attached TUI does not lend its pane to the server, and N arbitrary
|
|
168
|
+
clients in different sessions have no adjacency claim. Missing home/app-server rejects
|
|
169
|
+
rather than guessing a client pane or creating/supervising either resource.
|
|
170
|
+
|
|
171
|
+
Three ownership atoms remain separate:
|
|
172
|
+
|
|
173
|
+
1. `entwurf install-codex-birth` owns `$CODEX_HOME/hooks.json` — one whole file, ours or
|
|
174
|
+
absent — plus its launcher and import closure under `$XDG_DATA_HOME/entwurf/codex-birth`.
|
|
175
|
+
No root: every path belongs to the operator. The vendor gates a user-layer declaration on
|
|
176
|
+
ONE interactive "Trust all", which entwurf never answers, pre-seeds or computes; the
|
|
177
|
+
receipt is read as its own doctor axis, and until it exists setup is honestly non-green.
|
|
178
|
+
2. `entwurf install-codex-mcp` owns `[mcp_servers.entwurf-bridge]` in
|
|
179
|
+
`$CODEX_HOME/config.toml`, including exact `env_vars` forwarding for `CODEX_HOME`,
|
|
180
|
+
Entwurf garden/control roots, and `TMUX`/`TMUX_PANE`. This explicit name boundary
|
|
181
|
+
keeps custom roots and the app-server seat intact without storing their values.
|
|
182
|
+
3. `entwurf install-codex-statusline` owns only `thread-title` within
|
|
183
|
+
`tui.status_line`. Birth calls `thread/name/set`, so the visible title is the garden id.
|
|
184
|
+
|
|
185
|
+
All three have state-backed doctors and inverses. Symlinked or foreign config is a
|
|
186
|
+
named refusal, not an adoption. Entwurf never installs Codex or its credentials.
|
|
187
|
+
|
|
188
|
+
Sender identity is request-scoped. The bridge requires the complete Codex metadata
|
|
189
|
+
tuple — `_meta.threadId`, `_meta.x-codex-turn-metadata.session_id`, and
|
|
190
|
+
`_meta.x-codex-turn-metadata.thread_id` — to agree, then joins that native id through
|
|
191
|
+
the addressable V3 record reader. Missing or conflicting fields refuse; there is no
|
|
192
|
+
parent-pid fallback. A complete pi env claim or other native claim must also agree.
|
|
193
|
+
This is load-bearing because every attached TUI shares the app-server ancestry.
|
|
194
|
+
|
|
195
|
+
The native-push adapter probes `thread/loaded/list`. A missing socket, malformed
|
|
196
|
+
handshake, protocol failure, or absent loaded target is `native-push-probe-indeterminate`
|
|
197
|
+
or dead as defined by the probe result; no mailbox fallback exists. Delivery uses the
|
|
198
|
+
measured one-shot `codex queue` command. Unlike Antigravity, Codex delivery has **zero
|
|
199
|
+
retry**: losing stdout after vendor acceptance must not replay the user's message.
|
|
200
|
+
|
|
201
|
+
Direct injection carries the **mailbox-serialized trusted sender envelope**, not the raw
|
|
202
|
+
message. This rail has neither the control socket's RPC framing nor a mailbox file, so the
|
|
203
|
+
envelope rides in the body through the same `formatMetaMailboxBody` SSOT the mailbox rail
|
|
204
|
+
uses — one rail for both native-push backends, no per-backend branch. It is rendered once,
|
|
205
|
+
before delivery, so Antigravity's one permitted re-probe retry replays byte-identical
|
|
206
|
+
content. A caller with no authoritative sender still injects the raw message; an envelope is
|
|
207
|
+
never fabricated. #95 measured the cost of the old raw behaviour: a fresh sibling's
|
|
208
|
+
nonce-only callback landed in a Codex thread as bare text, so the Codex citizen could not
|
|
209
|
+
name its caller and the callback was uncorrelatable.
|
|
210
|
+
|
|
211
|
+
Visible fresh runs:
|
|
212
|
+
|
|
213
|
+
```text
|
|
214
|
+
existing tmux session: codex
|
|
215
|
+
operator-owned app-server + supported Codex TUIs
|
|
216
|
+
codex --remote unix://<default socket> --model <explicit model>
|
|
217
|
+
--dangerously-bypass-approvals-and-sandbox <callback-first prompt>
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
With `placement` omitted, the fresh composition resolves the exact existing `codex` session name
|
|
221
|
+
to its native `$id` before mutation. Other backends retain caller-session default placement; an
|
|
222
|
+
explicit seat remains an expert override. The amended preflight must certify the state-backed birth
|
|
223
|
+
closure digests, vendor trust receipt, exact MCP/env boundary, `thread-title`, and app-server socket
|
|
224
|
+
before tmux mutation. The callback spelling is `mcp__entwurf_bridge__entwurf_v2`; the new garden id
|
|
225
|
+
comes only from its sender envelope. There is no Codex resume, watcher, session/app-server creator,
|
|
226
|
+
or lifecycle supervisor.
|
|
227
|
+
|
|
228
|
+
The 2026-09-11 Linux run used Codex 0.153.4 and the default app-server: the production
|
|
229
|
+
probe found loaded thread `01a08bff-4efa-7071-9cac-b6d29da5f126`; native-push and a
|
|
230
|
+
public MCP `entwurf_v2` call woke its visible TUI; a real authenticated request returned
|
|
231
|
+
`agentId=meta-session/codex`, `replyable=true`; and a source birth hook minted garden
|
|
232
|
+
`20260911T005221-fc7c47` in an isolated store. Those receipts are preserved as
|
|
233
|
+
**pre-amendment focused delivery/identity evidence**, not qualification of the current
|
|
234
|
+
candidate.
|
|
235
|
+
|
|
236
|
+
The amended same-session acceptance (**A**) passed on local candidate `6e28c9e` at Codex
|
|
237
|
+
0.153.4. Receipt `.probe-artifacts/a95-live-20260911T162152-6e28c9e.log` (SHA-256
|
|
238
|
+
`e159f8fd1cf23cb1abd7782dc9e24cf9604add6b61ae24b7fd5260f16dfc2795`) records 50
|
|
239
|
+
assertions and exit 0: real initial Pi `20260911T162155-0db222` opened and addressed Codex
|
|
240
|
+
`20260911T162210-a974fe` / thread `01a08f58-588b-7620-a67c-cc0f6c62a79e`; Codex then
|
|
241
|
+
opened outbound Pi `20260911T162238-7dcdaa` and correlated its exact callback nonce and
|
|
242
|
+
sender garden id. The operator app-server, initial Pi, Codex, and outbound Pi all resolved to
|
|
243
|
+
tmux session `$158`. Cleanup removed only smoke windows `@355`, `@356`, and `@357`,
|
|
244
|
+
preserved all three records/transcripts, and left operator app-server PID `155166` and
|
|
245
|
+
`$158/@351/%351` alive.
|
|
246
|
+
|
|
247
|
+
That receipt established the mechanism of the now-selected deployment, but its initial Pi also sat
|
|
248
|
+
in the app-server session and predates the fixed-home default. The stronger explicit-home acceptance
|
|
249
|
+
passed on 2026-09-12. Receipt `.probe-artifacts/20260912T140745-codex-home-live-green.log`
|
|
250
|
+
(SHA-256 `09e79bd1b62962f8a11d647ee456a71b11965b6792c7972d97ac4992119c91d7`)
|
|
251
|
+
records 57 assertions and exit 0. The operator app-server stayed at `$158/@390/%390`; real initial Pi
|
|
252
|
+
`20260912T140748-355654` opened outside the home at `$150/@397`, omitted-placement Codex
|
|
253
|
+
`20260912T140800-8bc8d9` / thread `01a09403-e232-76b0-af9a-5cbaed8d94a9` opened at `$158/@398`,
|
|
254
|
+
and Codex opened outbound Pi `20260912T140829-a08178` at `$158/@399`. The callbacks preserved exact
|
|
255
|
+
nonces `mux-fresh-call-5d28f8e5bc2acf275ded30ec` and
|
|
256
|
+
`mux-fresh-call-7a5fb4960dbb172843eb14fe`; initial Pi → Codex reported
|
|
257
|
+
`entwurf_v2 native-push → delivered`, Codex read back its live garden-id title through `thread/read`,
|
|
258
|
+
and every smoke-owned window was removed while the operator app-server remained alive.
|
|
259
|
+
|
|
260
|
+
Two red attempts tightened the acceptance rather than weakening it. The first reached correct home
|
|
261
|
+
placement but Codex interpreted “wait” as `wait_agent(timeout_ms=3600000)`, leaving its first turn
|
|
262
|
+
active; the prompt now requires ending the turn and forbids every wait tool. The second proved that a
|
|
263
|
+
model may reformat a receipt while copying it. That accepted run still travelled coordinate reports
|
|
264
|
+
between citizens and checked them against Pi/Codex source results. A later prepare run exposed the
|
|
265
|
+
remaining flaw by truncating a report token: the amended gate removes intermediate model reports,
|
|
266
|
+
joins exact Pi toolCall/toolResult rows and structured Codex `thread/read` MCP items directly, and
|
|
267
|
+
reads garden ids only from raw callback events. Failure cleanup recovers the exact Codex thread from
|
|
268
|
+
its nonce callback, interrupts only its still-running smoke-owned turn, and closes only windows named
|
|
269
|
+
by joined source fresh-call results.
|
|
270
|
+
|
|
271
|
+
The amendment's own standalone acceptance then passed on 2026-09-12 (Codex 0.153.4): **48 assertions,
|
|
272
|
+
exit 0**, final source audit `initial-pi=3/3 completed exact` and `codex=3/3 completed exact`. Fixture
|
|
273
|
+
`20260912T232054-14c8e8` at `$150/@430`; initial Pi `20260912T232056-c0be9e` at `$150/@431`;
|
|
274
|
+
operator-owned app-server `1693273` at `$158/@390/%390`; omitted-placement Codex `20260912T232110-1cd889`
|
|
275
|
+
(thread `01a095fe-4f1a-7d93-8c5a-ed7539cf8930`) at `$158/@432`; Codex-opened Pi `20260912T232133-4ac684`
|
|
276
|
+
at `$158/@433`; final token `CODEX-PI-FINAL-6QWDSELJ` carried `PI_CALLBACK_FROM=20260912T232133-4ac684`,
|
|
277
|
+
`PI_SESSION_ID=$158`, `PI_WINDOW_ID=@433` into the fixture mailbox, which read it. Cleanup reclaimed
|
|
278
|
+
`@433`, `@432`, `@431` — every one named by a joined source fresh-call result, with no tmux inventory scan
|
|
279
|
+
and no mailbox prose promoted to authority. Artifact `.probe-artifacts/codex-fresh-live-fZccoK/`
|
|
280
|
+
(`run-manifest.json` sha256 `05f20f00…`). The 57-assertion first-admission receipt above is preserved as
|
|
281
|
+
its own pre-amendment axis; the two counts are different contracts, not a regression.
|
|
282
|
+
|
|
283
|
+
That run also closed a defect the amendment had introduced. A source path read once at callback
|
|
284
|
+
correlation froze out a record that gained `transcriptPath` 34s later, so the observer saw nothing while
|
|
285
|
+
the chain actually completed — the preceding red run's Codex thread holds a completed final `entwurf_v2`
|
|
286
|
+
result naming `PI_WINDOW_ID=@426`, and its two orphan windows were reclaimed only after their own joined
|
|
287
|
+
source receipts named them (`@425` backend codex from the initial Pi, `@426` backend pi from the Codex
|
|
288
|
+
thread; cleanup log preserved at `.probe-artifacts/codex-fresh-live-FblYLs/source-authorized-cleanup.log`,
|
|
289
|
+
sha256 `07fe18fc…`, alongside `run-manifest.json` sha256 `62a538fd…`). The path is now re-read while the
|
|
290
|
+
cache is empty. Note honestly what the green run does and does not prove: its manifest carries neither
|
|
291
|
+
`initialPiTranscriptResolvedLate` nor `sourcePathUnresolved`, so the late-write timing did not recur and
|
|
292
|
+
the repair is proven by its deterministic claim, not by this LIVE.
|
|
293
|
+
|
|
294
|
+
**Repeat acceptance inside the aggregate release gate (2026-09-13).** The same acceptance ran again as
|
|
295
|
+
the `smoke-codex-fresh-live` MUST step of `release-gate --cut` and passed at 48 assertions: fixture
|
|
296
|
+
`20260913T065136-59d143` at `$187/@442`, initial Pi `20260913T065138-ad5f57` at `$187/@447`,
|
|
297
|
+
omitted-placement Codex `20260913T065151-4b6078` (thread `01a0979a-edc4-7570-a29b-50f7e48cf298`) at
|
|
298
|
+
`$158/@448`, Codex-opened Pi `20260913T065213-0811e6` at `$158/@449`, against the same operator-owned
|
|
299
|
+
app-server at `$158/@390/%390`. Artifact `.probe-artifacts/codex-fresh-live-2oId4C/` (`run-manifest.json`
|
|
300
|
+
sha256 `2cff6f08…`). Note the fixture seat differs from the standalone run: the aggregate builds its own
|
|
301
|
+
tmux session (`$187`), while the Codex legs still resolve to the exact `codex` home. That gate reported
|
|
302
|
+
MUST PASS=24 FAIL=0 SKIP=0 and `cut: OK`. Keep the three Codex acceptances apart — 57-assertion
|
|
303
|
+
pre-amendment first admission, 48-assertion standalone amended (`fZccoK`), and this 48-assertion
|
|
304
|
+
aggregate repeat (`2oId4C`).
|
|
305
|
+
|
|
306
|
+
An earlier attempt at the identical source fingerprint failed two model-in-loop MUST steps and is kept
|
|
307
|
+
as an observation rather than a defect: a callback nonce arrived one character short and an addressed
|
|
308
|
+
instruction carried the wrong payload. Joined source receipts showed target, rail, and delivery were all
|
|
309
|
+
correct, so both oracles refused for the right reason and nothing in the product was changed.
|
|
310
|
+
|
|
311
|
+
Unrestricted attached-TUI parity (**B**) is explicitly outside this support claim. The exact vendor
|
|
312
|
+
checkout `rust-v0.153.4` at `3d2ee51ca2d5db578f328aa75e20aa22c0197c9a` found no public
|
|
313
|
+
request→attached-TUI-seat carrier: process-local `ConnectionId` does not cross into thread/core/MCP/hook
|
|
314
|
+
state, and the TUI-local dynamic task MCP is a closed vendor namespace. That source result now bounds
|
|
315
|
+
the topology instead of blocking the explicit home. Manual pane/process guessing and hidden manager
|
|
316
|
+
behaviour remain invalid; explicit `placement.tmuxSession` is an operator-named expert override, not
|
|
317
|
+
an inferred seat. The gate strips ambient `PI_SESSION_ID`/`PI_AGENT_ID`; a fixture may preserve receipts
|
|
318
|
+
but cannot substitute for the initial visible record-backed Pi turn.
|
|
319
|
+
|
|
320
|
+
Run the clause-7 invocation from a tmux session other than `codex`; the explicit app-server PID must belong to the operator-owned app-server seated in `codex`, and both models are explicit:
|
|
321
|
+
|
|
322
|
+
```bash
|
|
323
|
+
LIVE=1 \
|
|
324
|
+
ENTWURF_CODEX_APP_SERVER_PID=<existing-app-server-pid> \
|
|
325
|
+
ENTWURF_CODEX_FRESH_MODEL=<codex-model> \
|
|
326
|
+
ENTWURF_CODEX_FRESH_PI_MODEL=<pi-model> \
|
|
327
|
+
./run.sh smoke-codex-fresh-live
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
This is the intended gate entrypoint, not acceptance by command name. The accepted receipt above
|
|
331
|
+
has a fixture only collecting evidence: a real visible record-backed Pi opens Codex from outside the
|
|
332
|
+
home, and the later exact callback and bidirectional delivery receipts close the topology claim.
|
|
191
333
|
|
|
192
334
|
### Copilot CLI: one citizen, two rails, one pending receipt
|
|
193
335
|
|