@junghanacs/entwurf 0.14.1 → 0.15.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 +8 -5
- package/CHANGELOG.md +113 -0
- package/DELIVERY.md +73 -3
- package/README.md +55 -4
- package/VERIFY.md +6 -6
- package/demo/README.md +3 -1
- package/demo/demo-baseline.sh +12 -1
- package/demo/demo.sh +9 -1
- package/docs/acp-backend-rail.md +103 -4
- package/docs/external-mcp-host.md +26 -4
- package/docs/setup-clean-host.md +3 -3
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +8 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/copilot-fresh-preflight.js +253 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +10 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +102 -28
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +77 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook-copilot.js +288 -0
- package/mcp/entwurf-bridge/dist/scripts/doctor-pi-provider.js +139 -47
- package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +294 -0
- package/mcp/entwurf-bridge/src/index.ts +10 -6
- package/mcp/entwurf-bridge/tsconfig.build.json +17 -6
- package/package.json +23 -12
- package/pi/copilot-receive/entwurf-receive/extension.mjs +323 -0
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/meta-bridge-copilot/.claude-plugin/marketplace.json +11 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/.claude-plugin/plugin.json +5 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/hooks/hooks.json +7 -0
- package/pi/meta-bridge-copilot/entwurf-meta-receive-copilot/scripts/copilot-hook-launch.sh +85 -0
- package/pi-extensions/entwurf-control.ts +17 -8
- package/pi-extensions/lib/acp/backend.ts +229 -9
- package/pi-extensions/lib/copilot-fresh-preflight.ts +251 -0
- package/pi-extensions/lib/meta-sender-identity.ts +10 -2
- package/pi-extensions/lib/meta-session.ts +102 -29
- package/pi-extensions/lib/mux-fresh-call.ts +82 -11
- package/pi-extensions/meta-bridge-hook-copilot.ts +323 -0
- package/run.sh +389 -26
- package/scripts/agy-bridge-config.py +47 -13
- package/scripts/agy-bridge.sh +73 -23
- package/scripts/check-acp-prompt-lifecycle.ts +221 -9
- package/scripts/check-copilot-birth-hook.ts +497 -0
- package/scripts/check-copilot-launch.ts +395 -0
- package/scripts/check-copilot-receive-arm.ts +734 -0
- package/scripts/check-copilot-statusline.ts +122 -0
- package/scripts/check-entwurf-bridge-boot.ts +28 -0
- package/scripts/check-entwurf-capabilities.ts +25 -6
- package/scripts/check-fresh-cut-gate.sh +92 -23
- package/scripts/check-gate-qualification.ts +10 -3
- package/scripts/check-install-container.sh +2 -2
- package/scripts/check-install-surface.ts +1 -1
- package/scripts/check-meta-capability-source.ts +89 -5
- package/scripts/check-meta-doctor-oracle.sh +26 -0
- package/scripts/check-meta-manifest-schema.py +38 -0
- package/scripts/check-meta-receiver-marker.ts +25 -2
- package/scripts/check-meta-session.ts +32 -0
- package/scripts/check-probe-bridge-command.ts +201 -0
- package/scripts/check-release-gate-outcomes.ts +54 -1
- package/scripts/copilot-bridge-doctor.sh +209 -0
- package/scripts/copilot-bridge-install.sh +224 -0
- package/scripts/copilot-launch.sh +236 -0
- package/scripts/copilot-mcp-bridge.sh +177 -0
- package/scripts/copilot-mcp-config.py +221 -0
- package/scripts/copilot-receive-bridge.sh +483 -0
- package/scripts/copilot-statusline-bridge.sh +149 -0
- package/scripts/copilot-statusline-config.py +201 -0
- package/scripts/copilot-statusline.sh +68 -0
- package/scripts/dev-bin.sh +4 -1
- package/scripts/doctor-pi-provider.ts +155 -51
- package/scripts/meta-bridge-hook-log.sh +17 -5
- package/scripts/mutants/acp-prompt-lifecycle.json +25 -3
- package/scripts/mutants/bridge-command-boot.json +107 -0
- package/scripts/mutants/capability-cache.json +64 -0
- package/scripts/mutants/copilot-birth.json +155 -0
- package/scripts/mutants/copilot-launch.json +187 -0
- package/scripts/mutants/copilot-receive.json +263 -0
- package/scripts/mutants/fresh-cut.json +17 -0
- package/scripts/mutants/mux-fresh-call.json +216 -2
- package/scripts/mutants/pack-install.json +17 -0
- package/scripts/mutants/release-gate.json +13 -0
- package/scripts/probe-bridge-command.ts +330 -0
- package/scripts/raw-async-delivery/README.md +203 -1
- package/scripts/raw-async-delivery/copilot-enqueue-addressed.sh +35 -0
- package/scripts/raw-async-delivery/copilot-extension-receive/extension.mjs +123 -0
- package/scripts/raw-async-delivery/copilot-ui-server-probe.mjs +337 -0
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-agy-install-state.sh +76 -2
- package/scripts/smoke-copilot-mcp-state.sh +153 -0
- package/scripts/smoke-copilot-statusline-state.sh +131 -0
- package/scripts/smoke-entwurf-chain-live.ts +1 -1
- package/scripts/smoke-entwurf-v2-matrix-live.ts +2 -2
- package/scripts/smoke-mux-fresh-call-live.ts +3 -1
- package/scripts/smoke-mux-lifecycle-live.ts +4 -2
- package/scripts/smoke-pi-provider-state.sh +135 -6
- package/scripts/smoke-resident-garden-guard.sh +2 -2
- package/scripts/tsconfig.json +1 -0
package/AGENTS.md
CHANGED
|
@@ -28,9 +28,9 @@ For agents that own this repo: invariant principles and reproducible verificatio
|
|
|
28
28
|
- **entwurf-core (v2)** owns garden-id addressing, peer facts, liveness interfaces, dispatch decisions, rail choice, and delivery evidence.
|
|
29
29
|
- **Record authority** owns citizen identity. Every addressable citizen uses the same V3 `MetaIdentity` schema. `backend` selects capability/rail behavior; it does not create an identity hierarchy.
|
|
30
30
|
- **pi adapter** attaches a pi session to a record at `session_start`, hosts the record-keyed control socket, and exposes the native pi tool surface.
|
|
31
|
-
- **Native bridges** register already-running native sessions without taking over their transcript or auth: Claude Code
|
|
31
|
+
- **Native bridges** register already-running native sessions without taking over their transcript or auth: Claude Code and Copilot CLI are mailbox/self-fetch (a Claude hook arms the watch; a forked Copilot extension holds it); Antigravity is probe-backed native-push. Codex has archived probe evidence, but its managed native lane was declined because pi already supplies the official GPT provider path; do not duplicate it as a native citizen or ACP backend.
|
|
32
32
|
- **ACP plugin** registers provider `entwurf` inside a pi host session and drives a backend under an isolated overlay. The host pi session is already a record-backed socket citizen; the plugin does not mint another citizen/socket/peer layer.
|
|
33
|
-
- **mux is launch-only and deliberately small.** Shipped: the tmux placement leaf (`mux-placement.ts` — inspect/append/close inside the caller's own session), the visible runtime launch composition (`mux-launch.ts`), the fresh-call composition (`mux-fresh-call.ts`), and the cwd-aware resume placement composition (`mux-resume-call.ts`). Fresh call is exposed as `entwurf_fresh_call`; visible same-id resume is `entwurf_resume_call`, composed at the two public surfaces by injecting `mux-resume-call` into the v2-side `entwurf-v2-visible-resume.ts`. The exact import graph is enumerated in [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11. `entwurf_v2` behavior is unchanged and delivery still never imports launch. Fresh call learns a new sibling's garden id from the CALLBACK it makes, never from a lookup — so the pre-injected-token → identity-lookup design (rail §6) is **closed, not paused**. Do not reopen it without new evidence and explicit GLG re-approval. Fresh-call requires one explicit model and passes it in each runtime's measured CLI dialect (Pi `--model <provider/model>`, Claude Code `--model=<id-or-alias>`); it also takes ONE optional literal absolute `cwd` (#73 — omitted/`""` means the caller's own directory; no trim, no realpath, no project-name resolver; classified by the shared `classify-tmux-cwd.ts` leaf; the receipt echoes the REQUEST only), so a cross-repo fresh sibling is a fresh-call fact and never a reason to resume a dormant record. Resume takes only an existing target id and gets transcript/model/provider/cwd from its record. Do not grow either narrow carrier into a generic driver, harness profile, arbitrary command/env selection, or a second creation API. Ownership and import prohibitions: [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11.
|
|
33
|
+
- **mux is launch-only and deliberately small.** Shipped: the tmux placement leaf (`mux-placement.ts` — inspect/append/close inside the caller's own session), the visible runtime launch composition (`mux-launch.ts`), the fresh-call composition (`mux-fresh-call.ts`), and the cwd-aware resume placement composition (`mux-resume-call.ts`). Fresh call is exposed as `entwurf_fresh_call`; visible same-id resume is `entwurf_resume_call`, composed at the two public surfaces by injecting `mux-resume-call` into the v2-side `entwurf-v2-visible-resume.ts`. The exact import graph is enumerated in [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11. `entwurf_v2` behavior is unchanged and delivery still never imports launch. Fresh call learns a new sibling's garden id from the CALLBACK it makes, never from a lookup — so the pre-injected-token → identity-lookup design (rail §6) is **closed, not paused**. Do not reopen it without new evidence and explicit GLG re-approval. Fresh-call requires one explicit model and passes it in each runtime's measured CLI dialect (Pi `--model <provider/model>`, Claude Code `--model=<id-or-alias>`, Copilot `--model <name>` beside `--interactive <prompt>` and the explicit `--yolo` policy — a GLG width decision, 2026-08-25, after a callback-only `--allow-tool` grant stopped the sibling at every task tool); the Copilot backend opens through entwurf's OWN managed invocation (`entwurf copilot`), never the bare vendor, and its four required capabilities — birth, MCP hand, receiver, visible footer — are decided by `copilot-fresh-preflight.ts` BEFORE the tmux mutation, so a missing unit is a named refusal instead of a dead window; it also takes ONE optional literal absolute `cwd` (#73 — omitted/`""` means the caller's own directory; no trim, no realpath, no project-name resolver; classified by the shared `classify-tmux-cwd.ts` leaf; the receipt echoes the REQUEST only), so a cross-repo fresh sibling is a fresh-call fact and never a reason to resume a dormant record. Resume takes only an existing target id and gets transcript/model/provider/cwd from its record. Do not grow either narrow carrier into a generic driver, harness profile, arbitrary command/env selection, or a second creation API. Ownership and import prohibitions: [docs/mux-launch-rail.md](./docs/mux-launch-rail.md) §11.
|
|
34
34
|
- **One delivery verb:** `entwurf_v2` addresses an existing garden id. Current routes are live control-socket send, active self-fetch mailbox enqueue, and probe-alive native-push. NO route starts a process: the hidden background resume for a dormant citizen was withdrawn under the visible-first rule, so a dormant in-domain citizen rejects as `dormant-fire-forget-unsupported` and the intent axis is single-valued. Every other complementary state pair rejects honestly too. Fresh creation is a separate verb — `entwurf_fresh_call` — and it returns a launch receipt only; the new sibling's address arrives asynchronously as the sender envelope of its nonce callback.
|
|
35
35
|
|
|
36
36
|
## Hard Rules
|
|
@@ -41,7 +41,7 @@ For agents that own this repo: invariant principles and reproducible verificatio
|
|
|
41
41
|
4. **Dispatch is computed from live facts.** Never store liveness. Never infer send/resume from session type before resolving the target and probing its rail.
|
|
42
42
|
5. **Rejects are real.** Wrong intent, dead/drifted identity, undeliverable mailbox, ambiguous address, or indeterminate probe returns a reject and mutates nothing. No cosmetic success or silent fallback.
|
|
43
43
|
6. **MCP is explicit.** Only explicit `mcpServers` wiring. No ambient `~/.mcp.json` scan or automatic retrieval.
|
|
44
|
-
7. **Meta-record store contract is one contract.** Record body is authority; filename must agree with the body; every active entry is a regular non-symlink file readable by the live V3 schema; `nativeSessionId` ownership is unique. Identity writers and doctor certify the whole active store before writing. Address-bearing reads use `readAddressableMetaIdentity`; targeted relay reads keep the documented per-entry contract. `readStoreRecordFile`/`O_NOFOLLOW` and the lstat policy layer are both load-bearing—do not merge or bypass them. No legacy reader/migrator: quiesce and run `entwurf meta-bridge-fresh-cut` when the generation is unreadable. Source and gates: `meta-session.ts`, `check-meta-*`, `check-fresh-cut-gate`.
|
|
44
|
+
7. **Meta-record store contract is one contract.** Record body is authority; filename must agree with the body; every active entry is a regular non-symlink file readable by the live V3 schema; `nativeSessionId` ownership is unique. Identity writers and doctor certify the whole active store before writing. Address-bearing reads use `readAddressableMetaIdentity`; targeted relay reads keep the documented per-entry contract. `readStoreRecordFile`/`O_NOFOLLOW` and the lstat policy layer are both load-bearing—do not merge or bypass them. No legacy reader/migrator: quiesce and run `entwurf meta-bridge-fresh-cut` when the generation is unreadable. An unknown-backend defect is a stale deployed reader, not a rotten generation: redeploy the sibling unit; do not fresh-cut. `doctor-meta-bridge` already names that — run it after `META_BACKENDS` changes. Source and gates: `meta-session.ts`, `check-meta-*`, `check-fresh-cut-gate`.
|
|
45
45
|
8. **GC reclaims process resources, never memory/data.** Records and transcripts are preserved or archived; they are not casually deleted.
|
|
46
46
|
9. **This is not a second harness.** No prompt reconstruction, transcript hydration, tool-result ledger, credential mediation, or harness emulation. Each backend owns auth and transcript state.
|
|
47
47
|
10. **Native-push is its own rail.** It is not a mailbox or pi socket in disguise. Antigravity replyability is record-backed plus probe-alive; no receiver marker, watch state, or resume authority is invented for it.
|
|
@@ -89,7 +89,7 @@ A `--entwurf-control` pi session is a citizen for the same reason a native bridg
|
|
|
89
89
|
|
|
90
90
|
- **control-socket domain (currently `pi`)**: socket liveness, per-target lock, live send, and a dormant cell that rejects.
|
|
91
91
|
- **No relaunch transport exists inside delivery.** `spawn-bg` — a detached, window-less resume child — was removed under the visible-first rule, not deprecated behind a reject, and `entwurf_v2` still starts no process: a dormant socket-domain citizen is refused as `dormant-fire-forget-unsupported`. Reopening one is the separate lifecycle verb `entwurf_resume_call`, which is pi-only (`target-not-pi` otherwise), returns a LAUNCH receipt and an OBSERVATION receipt that are never merged, releases its per-gid lock on every path, and on an unobserved socket leaves the visible window open rather than retrying. No watcher, no retry, no supervisor. Do not re-route it through `entwurf_v2` and do not describe a spawn domain that does not exist.
|
|
92
|
-
- **self-fetch domain (
|
|
92
|
+
- **self-fetch domain (Claude Code, Copilot CLI)**: active receiver + mailbox deliverability; no resume authority. The two arm that receiver through different vendor surfaces — a Claude hook that emits watchPaths, a Copilot first-party extension that holds the watch in a forked child — and the marker records which, because the pid a reader verifies differs.
|
|
93
93
|
- **native-push domain (currently Antigravity)**: adapter probe + direct injection; no mailbox and no resume authority.
|
|
94
94
|
- `origin: "pi-session" | "meta-session" | "external-mcp"` records sender provenance. It is not the citizen identity schema and not a hierarchy.
|
|
95
95
|
- `entwurf_peers` reports record citizens and liveness facts only. It never embeds routing verbs or socket addresses for peers.
|
|
@@ -111,6 +111,7 @@ A `--entwurf-control` pi session is a citizen for the same reason a native bridg
|
|
|
111
111
|
- A new issue brings the best available observation plus an executable next measurement. Recovering a missing signature may be the first acceptance; an idea with neither evidence nor a next measurement is not an issue.
|
|
112
112
|
- No collection points, umbrella trackers, or fallout buckets. Merge issues only when they share one cause and one acceptance.
|
|
113
113
|
- Sweep manually after a release and before opening an issue. Solved work closes at its durable SHA; it does not wait for the next release.
|
|
114
|
+
- **An issue body is a snapshot; the thread is the live contract.** A body written before GLG stated what the work is *for* will disagree with the thread, and a reader who opens only the body inherits the stale half — including its fences, which is how a fence once forbade the very deliverable the lane existed to produce (#82, 2026-08-20). When they disagree the thread wins. Whoever notices owes the body an edit that strikes the withdrawn clause and says why it was there; deleting it silently makes the queue tidy and the lesson invisible.
|
|
114
115
|
|
|
115
116
|
## Verification
|
|
116
117
|
|
|
@@ -180,7 +181,7 @@ implement → affected focused gates → independent review → one amendment bu
|
|
|
180
181
|
- 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`.
|
|
181
182
|
- Root pi extensions import TypeBox through `@earendil-works/pi-ai`; do not mix direct `@sinclair/typebox` types.
|
|
182
183
|
- MCP/scripts use explicit `.ts` imports where Node strip-types requires them. Installed operator surfaces route to compiled JS.
|
|
183
|
-
- pi runtime range is `>=0.84.
|
|
184
|
+
- pi runtime range is `>=0.84.3 <0.85` with devDep exact `0.84.3`; 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.
|
|
184
185
|
- 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.
|
|
185
186
|
|
|
186
187
|
## Working Style
|
|
@@ -206,12 +207,14 @@ An overgrowth is built from locally correct steps; what fails is the absence of
|
|
|
206
207
|
- **Unrelated meta-infra never rides a capability lane.** The source-adjacent gate/mutant that proves a capability's contract belongs in the same change as that capability — the removal/repair rule above is untouched. What stays out of a feature commit candidate is unrelated verification machinery: scheduling rework, selectors, caches, receipts, floor restructuring. That pain is recorded and handled in its own subtraction lane later.
|
|
207
208
|
- **Stop signal — evidence outgrowing the product.** When verification/meta-tool changes grow larger than the capability change they serve, stop and report to GLG. This is an operator-judgment trigger, deliberately not a mechanized ratio gate.
|
|
208
209
|
- **Claim only what the evidence carries.** "The full floor was green once on the declared candidate" is strong enough; a stronger sentence mints proof obligations, and those obligations mint subsystems.
|
|
210
|
+
- **A claim that crosses sessions carries its evidence state.** Measured here (name the receipt), read at `file:line`, read from an external artifact (name the path), inherited and unchecked (name the source) — and design proposals in a box of their own, since a proposal is adopted or decided differently, never measured. This repo is where siblings from many models each get a few turns, so a bare sentence costs the next one its turn re-deriving the ground, and leaves it only "believe or refute" when the honest move is "that carries no receipt, so I measured it." Retire claims, not people. Receipts in host-local paths do not travel: paste the decisive lines into the artifact that crosses.
|
|
209
211
|
- **Risk classes are not equal.** Data loss, identity authority, false delivery success, install destruction, and secrets get fail-closed strength. Doc tense, future possibility, and total environment-byte binding get repaired when seen — they do not justify new gate machinery.
|
|
210
212
|
|
|
211
213
|
## Next and References
|
|
212
214
|
|
|
213
215
|
- [NEXT.md](./NEXT.md) — current priority and exact next move; branch work uses disposable `NEXT--<branch>.md`.
|
|
214
216
|
- [ROADMAP.md](./ROADMAP.md) — forward direction and deferred lanes.
|
|
217
|
+
- [docs/adding-a-harness.md](./docs/adding-a-harness.md) — **first entry point for putting a NEW harness in the garden.** The order the eight steps are actually walked in (lane choice, vendor measurement, backend registration, birth, statusline, MCP hand, sender identity, receive, grade), what each owes before the next may start, and which of the other docs owns each slice. It routes; it grants nothing — Hard Rule 7 remains the authority on the meta-record store contract its registration step touches, and the gates and doctors it names remain the truth.
|
|
215
218
|
- [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) — ACP adapter contract and current entry conditions.
|
|
216
219
|
- [DELIVERY.md](./DELIVERY.md) — delivery capability/evidence coordinates.
|
|
217
220
|
- [VERIFY.md](./VERIFY.md) / [BASELINE.md](./BASELINE.md) — verification protocol and recorded evidence.
|
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,119 @@ All notable changes to this project will be documented here. Format follows [Kee
|
|
|
4
4
|
|
|
5
5
|
## Unreleased
|
|
6
6
|
|
|
7
|
+
## 0.15.0 — 2026-08-25
|
|
8
|
+
|
|
9
|
+
This release admits Copilot CLI as a full self-fetch garden citizen — birth, an owned
|
|
10
|
+
MCP hand, record-backed sender identity, an installed first-party receive extension, and
|
|
11
|
+
a visible-fresh launch path — closing #82, and fixes the fresh-launch YOLO regression the
|
|
12
|
+
admission work exposed.
|
|
13
|
+
|
|
14
|
+
### Added
|
|
15
|
+
|
|
16
|
+
- **Copilot CLI is a self-fetch garden citizen.** `birthCopilotCitizen` upserts
|
|
17
|
+
`(backend:"copilot", nativeSessionId)` into the shared V3 record store, gives the
|
|
18
|
+
session a garden id, an owned `entwurf` MCP hand, a footer statusline slot showing that
|
|
19
|
+
id, and record-backed sender identity on every dispatched message. The receive rail is
|
|
20
|
+
an installed first-party extension (`run.sh install-copilot-receive`) that binds to the
|
|
21
|
+
V3 record, arms a watcher, and rings a doorbell the model drains with
|
|
22
|
+
`entwurf_inbox_read`; `wakeMode` is `self-fetch`, so dispatch reaches the mailbox rail —
|
|
23
|
+
armed sessions get `delivered`, unarmed or stale sessions get the honest
|
|
24
|
+
`mailbox-undeliverable` refusal. Launch is exclusively through the owned invocation
|
|
25
|
+
`entwurf copilot`, which sets `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` for that one
|
|
26
|
+
process; a session started any other way is silently inert by design, and
|
|
27
|
+
`doctor-copilot-receive` reads the live CLI environment to catch that class. (#82)
|
|
28
|
+
- **Fresh Copilot siblings are admitted through the same preflight contract as birth.**
|
|
29
|
+
`copilot-fresh-preflight.ts` decides birth, MCP hand, receiver, and visible footer
|
|
30
|
+
BEFORE the tmux mutation, so a missing capability is a named refusal instead of a dead
|
|
31
|
+
window. `entwurf_fresh_call` takes one explicit model in Copilot's measured CLI dialect
|
|
32
|
+
(`--model <name>` beside `--interactive <prompt>`) and opens through `entwurf`'s own
|
|
33
|
+
managed invocation, never the bare vendor binary. (#82)
|
|
34
|
+
- **Visible-fresh and D6 receive are LIVE-accepted on one host.** 2026-08-23 D6 receive
|
|
35
|
+
acceptance (garden `20260823T181316-d9f6ba`, CLI 1.0.80): `joined → armed → doorbell →
|
|
36
|
+
rang`, mailbox enqueue/read timestamps, and a model reply on the same
|
|
37
|
+
record/native/garden-id chain. 2026-08-25 visible-fresh acceptance: launch window `@89`,
|
|
38
|
+
nonce `mux-fresh-call-690529ae99f99faa2252aefb`, exact-callback garden
|
|
39
|
+
`20260825T085721-f68be0`, one `entwurf_v2` mailbox enqueue plus a same-garden reply, and
|
|
40
|
+
an operator-observed footer garden id on a healthy multi-turn window. Both rows are
|
|
41
|
+
evidence level L4 (one host) and stay unmerged; visible fresh is operator-metered and is
|
|
42
|
+
not a release-gate MUST.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- **Fresh Copilot siblings now default to `--yolo`, matching the profile a human gets
|
|
47
|
+
from `entwurf copilot`.** `mux-fresh-call.ts` previously passed a callback-only
|
|
48
|
+
`--allow-tool=entwurf-bridge(entwurf_v2)` grant, which caused `copilot-launch.sh`'s
|
|
49
|
+
explicit-policy scan to suppress its own `--yolo` injection — every task-tool call then
|
|
50
|
+
stopped on a confirmation prompt the new sibling could not answer, making it practically
|
|
51
|
+
unusable. GLG operator LIVE on 2026-08-25 confirmed the missing `YOLO` footer and the
|
|
52
|
+
per-task-tool stalls; the fix restores the default without adding a permission
|
|
53
|
+
parameter to the fresh-call API or changing the manual `entwurf copilot` override
|
|
54
|
+
behavior. (#82 follow-up)
|
|
55
|
+
- **Pi runtime pin moves to `0.84.3`.** Certified development pin and closed peer range
|
|
56
|
+
are now `0.84.3` / `>=0.84.3 <0.85`. `compat.ts` stayed byte-identical at the previous
|
|
57
|
+
bump but `loader.ts` did not, so the diff was read and judged reachable before moving
|
|
58
|
+
the ceiling; the argument is not reused across bumps and each future ceiling move is
|
|
59
|
+
judged on its own diff.
|
|
60
|
+
|
|
61
|
+
### Verification
|
|
62
|
+
|
|
63
|
+
- **`pnpm run check:full`** — PASS, exit 0, 406s standalone on the prepared HEAD.
|
|
64
|
+
- **`LIVE=1 ./run.sh release-gate <scratch> --cut`** — **MUST PASS=21 FAIL=0 SKIP=0,
|
|
65
|
+
BEHAVIOR PASS=1 FAIL=0 SKIP=0, `cut: OK`.** `check-gate-qualification` inside the gate
|
|
66
|
+
killed **252/252** mutants across 30 lanes. Log:
|
|
67
|
+
`/tmp/entwurf-release-gate-0.15.0.run2.fB2LLP/release-gate.log` (SHA-256
|
|
68
|
+
`9a00a22e8b4ca715ad0b955b51c99a2bacc385bf0c225180026948a4618e5ff6`).
|
|
69
|
+
- A first attempt on the same prepared HEAD (scratch `.../entwurf-release-gate-0.15.0.7yUIFH`)
|
|
70
|
+
hit one MUST FAIL in `smoke-mux-lifecycle-live`'s cleanup launcher-integrity self-fence:
|
|
71
|
+
all 78 lifecycle assertions passed, but the Claude Code launcher symlink changed target
|
|
72
|
+
and content mid-run (`2.1.243`→`2.1.245`) because auto-update was still on the default
|
|
73
|
+
channel. GLG pinned `autoUpdatesChannel: stable` before the rerun above; this was an
|
|
74
|
+
environment race during the LIVE run, not a defect in the 0.15.0 candidate.
|
|
75
|
+
|
|
76
|
+
### Notes
|
|
77
|
+
|
|
78
|
+
- Copilot's D7 grade is PARTIAL: reply and read receipts are observed; completion
|
|
79
|
+
taxonomy and long-haul operation are not. D3 (second-session isolation of an owned
|
|
80
|
+
invocation) is PENDING — observed once, but the decisive log was lost to scratch
|
|
81
|
+
cleanup before it could be preserved; re-measurement is tracked outside this release.
|
|
82
|
+
- #76 (subscription-first refusal of `openrouter/*` sibling launches), #78
|
|
83
|
+
(macOS/native-Windows portability evidence), #80 (public vocabulary), #83, #84, #85, and
|
|
84
|
+
the remaining #72 field-cause investigation stay outside this release.
|
|
85
|
+
|
|
86
|
+
## 0.14.2 — 2026-08-20
|
|
87
|
+
|
|
88
|
+
This patch makes bridge availability a property of the exact invocation each harness will run, preserves child-exit facts across ACP transport closure, and records Copilot delivery as probe evidence without admitting a new citizen rail.
|
|
89
|
+
|
|
90
|
+
### Changed
|
|
91
|
+
|
|
92
|
+
- **ACTION REQUIRED — the certified runtime floor is now Pi `0.84.2`, with Claude ACP adapter `0.70.0`.** Pi's exact development pin and closed peer range move to `0.84.2` / `>=0.84.2 <0.85`; Claude ACP `0.70.0`, ACP SDK `1.3.0`, and Claude Code `>=2.1.217` are the measured support coordinates. Re-run setup after upgrading so the installed package and stable bridge launcher agree with this release. (#79)
|
|
93
|
+
- **Every live-spend harness default is now `openai-codex/gpt-5.6-luna`.** The cross-harness chain, the v2 matrix, mux fresh/lifecycle, the resident garden guard, and the `entwurf-dev` skill's Pi default all name the cheaper model; the `ENTWURF_LIVE_TARGET` / `ENTWURF_CHAIN_GPT_TARGET` / `SMOKE_RGG_MODEL` overrides are unchanged. Fixture model strings are deliberately untouched — they assert exact argv or routing and spend nothing. This is a cost decision, not a gate change: no step moved tier and the LIVE gate was re-earned on the new default rather than inherited. Antigravity has no harness-side model at all (the operator opens that conversation), so its free-account fence — `gemini-3.6-flash`, never a Pro tier — is recorded in `VERIFY.md` and the `run.sh` help.
|
|
94
|
+
- **Pi and Antigravity doctors boot the exact configured stdio invocation.** Runtime truth is separate from repair ownership: every effective Pi entry, including an unowned override, is probed without being overwritten; Antigravity preserves its configured `command`, `args`, and `env`. A valid MCP `initialize` response must arrive before `notifications/initialized` and `tools/list`, and the returned surface must equal the seven public Entwurf verbs. Closes #81.
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- **A direct-native Copilot raw probe records one bounded Linux observation without claiming support.** The current probe binds a unique marker body to `user.message.interactionId`, then to one `assistant.turn_start.turnId`, and accepts only assistant events from that turn; missing or ambiguous identity fails closed, the control session rejects any `user.message` or `assistant.*` event, and cleanup is bounded. The earlier 2026-08-19 L4 observation used a chronological slice on one workstation and its stdout was not archived, so it is not evidence that the corrected named-turn contract has run LIVE. Copilot remains outside `MetaIdentity`, backend registries, `entwurf_v2`, native-push, fresh, and resume; admission work is tracked in #82.
|
|
99
|
+
|
|
100
|
+
### Fixed
|
|
101
|
+
|
|
102
|
+
- **ACP prompt failures no longer lose child exit facts when transport EOF arrives first.** A one-shot child-end latch gives an already-failed turn a bounded post-mortem settle before Entwurf teardown, preserving the original backend error plus lifecycle phase, exit code, signal, stderr tail, or an honest bounded absence. It adds no running-prompt timeout, replay, watcher, supervisor, or recovery API; #72 remains open for the natural retained-child death cause.
|
|
103
|
+
- **A configured bridge cannot pass because its name resolves, its defaults boot, or it answers `tools/list` before initialization.** Pi and Antigravity reject dead overrides, argument/environment-specific failures, invalid invocation shapes, malformed initialize replies, missing/extra verbs, and foreign or relocated launchers while retaining the rule that Entwurf never clobbers a launcher it does not own.
|
|
104
|
+
- **The release gate boots the operator's CONFIGURED Pi bridge invocation before it reaches the LIVE tier.** `check-bridge` only proves the launcher this checkout ships, so a relocated or shimmed `entwurf-bridge` that `command -v` resolves while `exec` returns 127 used to stay invisible until sixteen LIVE steps and real model spend later. `doctor-pi-provider` is now a release-gate MUST `run_step` — not LIVE-gated, with no skip arm — so that class fails in about a second instead of after a model turn. (#81 follow-up)
|
|
105
|
+
- **The bridge probe preserves the launcher's own stderr across fast exit and asynchronous stdin `EPIPE`.** It installs the pipe error guard before the first write, consumes newline JSON-RPC frames once, and waits for process exit plus stderr end before issuing the exit verdict, so a Node stack trace cannot replace the diagnostic the operator needs.
|
|
106
|
+
|
|
107
|
+
### Verification
|
|
108
|
+
|
|
109
|
+
- **Landing SHA `d0fb8e6a37d401fc5ef660c90c1051db4b0811e8`** passed exact-SHA GitHub Actions run [32230953648](https://github.com/junghan0611/entwurf/actions/runs/32230953648): `check`, `install-surface`, and `artifact-consumer` all concluded success. At that SHA the combined landing candidate passed focused bridge 11/11, Pi provider 52/52, Antigravity 177/177, qualification **184/184 killed**, and `pnpm run check:full` in 315s before push. Those two numbers belong to `d0fb8e6` and are kept as its record — they are not this release's shipped figures.
|
|
110
|
+
- **The accepted 0.14.2 candidate** passed qualification **185/185 killed** — the `release-gate` lane grew 11 → 12 with `PI-DOCTOR-IS-RELEASE-MUST`, added by `877b4da` — and `pnpm run check:full` in 207s standalone / 209s inside the gate (remeasured 2026-08-20; `run.sh` is a mutant subject, so the pre-edit 311s does not describe this tree). **185 is the shipped inventory.**
|
|
111
|
+
- **`LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.14.2.c5VqTP --cut` — MUST PASS=21 FAIL=0 SKIP=0, BEHAVIOR PASS=1 FAIL=0 SKIP=0, `cut: OK`.** Log: `/tmp/entwurf-release-gate-0.14.2.c5VqTP/release-gate.log` (SHA-256 `27346d86be4a1a96a8ea8cab97687fcce807e4fa4bd6e3d179b91f85dbbcbe53`). Both model-in-loop lifecycle steps ran on the new default: `smoke-entwurf-chain-live` and `smoke-mux-lifecycle-live` passed with `openai-codex/gpt-5.6-luna`, so the cheaper default is proven LIVE rather than assumed. Cortex stayed the documented on-demand axis and is not part of this aggregate.
|
|
112
|
+
- The new hermetic `check-probe-bridge-command` lane requires sequential initialization, exact tool equality, stderr preservation, bounded cleanup, and the stdin `EPIPE` guard; its `bridge-command-boot` qualification lane carries nine claims within the shipped 185-mutant inventory.
|
|
113
|
+
|
|
114
|
+
### Notes
|
|
115
|
+
|
|
116
|
+
- Snowflake Cortex has neither a subscription nor a free tier reachable from the source-owning host (measured 2026-08-20), so `smoke-acp-cortex-live` can only report protocol SKIP here. That is an absent axis, not a pass, and no other backend substitutes for it.
|
|
117
|
+
- Copilot is probe-only in this release. #82 owns authentication, permission, liveness, stale/crash, operator-session cleanup, durable LIVE evidence, and the final admit/reject decision.
|
|
118
|
+
- #76 (subscription-first refusal of `openrouter/*` sibling launches), #78 (macOS/native-Windows portability evidence), #80 (public vocabulary), and the remaining #72 field-cause investigation stay outside this patch.
|
|
119
|
+
|
|
7
120
|
## 0.14.1 — 2026-08-13
|
|
8
121
|
|
|
9
122
|
This patch fills the cross-repository creation gap in the visible mux lifecycle shipped in 0.14.0, so one operator tmux session can form siblings in multiple project roots without borrowing a dormant session as a cwd carrier.
|
package/DELIVERY.md
CHANGED
|
@@ -74,13 +74,22 @@ D8 robustness: partial reason="..."
|
|
|
74
74
|
|
|
75
75
|
## Current matrix
|
|
76
76
|
|
|
77
|
+
**Vocabulary.** *Owned* in this file names entwurf ownership of a concrete invocation,
|
|
78
|
+
installer, or config writer. Historical receipts may say *managed* for that same ownership
|
|
79
|
+
axis; neither word is an admission grade or a synonym of *supported*. A pre-contract probe
|
|
80
|
+
can be owned without being supported; a supported harness still has to walk
|
|
81
|
+
[`docs/adding-a-harness.md`](./docs/adding-a-harness.md) step 9.
|
|
82
|
+
|
|
77
83
|
| Harness / surface | Product status | Capability | Transport and boundary |
|
|
78
84
|
|---|---|---|---|
|
|
79
85
|
| **pi native Entwurf** | shipped | D7; D8 partial | Record-addressed Unix control socket. A record-less socket is diagnostic only and never dispatched. |
|
|
80
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. |
|
|
81
87
|
| **Antigravity / agy** | shipped | D6; D7 partial | Record-backed native-push through LS gRPC `agentapi send-message`; no mailbox or receiver marker. |
|
|
82
|
-
| **Codex app-server-backed TUI** | verified probe | D7; D8 unproven | WebSocket-over-UDS `turn/start` into a live `threadId`; status events expose completion. No
|
|
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. |
|
|
83
89
|
| **Codex embedded TUI** | deferred | D0 partial | No supported receive socket/hook on the measured standalone shape. |
|
|
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
|
+
| **Copilot CLI garden citizen** | branch candidate; 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
|
+
| **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. |
|
|
84
93
|
| **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. |
|
|
85
94
|
|
|
86
95
|
“Verified probe” means the transport worked in a reproducible raw probe but entwurf
|
|
@@ -111,7 +120,7 @@ directly through the native adapter, with one bounded re-probe retry. Replyabili
|
|
|
111
120
|
`record-backed identity ∧ probe-alive`; mailbox state does not exist on this rail, and no
|
|
112
121
|
rail has resume authority since the visible-first cut.
|
|
113
122
|
|
|
114
|
-
The
|
|
123
|
+
The owned bridge, statusline, and hook installers own separate configuration atoms.
|
|
115
124
|
Same-pid concurrent model invocation by multiple conversations is not claimed because
|
|
116
125
|
the pid/start-key sender marker would be last-writer-wins. Current operator checks are
|
|
117
126
|
in [BASELINE.md](./BASELINE.md); deterministic ownership and sender gates run in
|
|
@@ -122,10 +131,71 @@ in [BASELINE.md](./BASELINE.md); deterministic ownership and sender gates run in
|
|
|
122
131
|
Do not describe “Codex” as one delivery shape. The measured app-server-backed TUI can
|
|
123
132
|
accept `turn/start` for a live thread and report completion; the standalone embedded
|
|
124
133
|
TUI exposed no equivalent receive route. This remains archived method evidence, not a
|
|
125
|
-
shipping commitment: GLG
|
|
134
|
+
shipping commitment: GLG declined to own a native Codex invocation/install lane on 2026-08-01 because pi
|
|
126
135
|
already supplies the official GPT provider path. Entwurf will not duplicate it as a
|
|
127
136
|
native citizen or ACP backend. `turn/steer` is active-turn steering, not idle wake.
|
|
128
137
|
|
|
138
|
+
### Copilot CLI: one citizen, two rails, one pending receipt
|
|
139
|
+
|
|
140
|
+
The branch product owns the native citizen's birth, garden id, statusline, MCP hand,
|
|
141
|
+
outbound sender identity — and, since RAIL 5, the receiver. A real Copilot CLI 1.0.80
|
|
142
|
+
session minted a V3 record and sent under that record-backed garden id on 2026-08-21.
|
|
143
|
+
That proved who SENDS. Whether a reply LANDS is a different fact on a different process,
|
|
144
|
+
and the paragraphs below are the two halves of it: where the transport came from, and
|
|
145
|
+
what the owned product unit had to add before it could be dispatched to.
|
|
146
|
+
|
|
147
|
+
The missing receive transport was found and measured on 2026-08-23. Copilot's platform
|
|
148
|
+
package bundles its first-party extension SDK and bootstrap. With
|
|
149
|
+
`COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS`, the CLI forks an installed extension and
|
|
150
|
+
speaks JSON-RPC over the child's stdio; `joinSession()` binds the foreground session, and
|
|
151
|
+
the vendor-documented `fs.watch` → `session.send({mode:"enqueue"})` pattern wakes it.
|
|
152
|
+
An idle, never-typed-into session received a unique marker and returned it, then emitted
|
|
153
|
+
`session.idle`. A second armed process was observed to remain untouched, but its decisive
|
|
154
|
+
B log was not preserved before scratch cleanup, so D3 isolation remains an admission
|
|
155
|
+
rerun rather than a durable acceptance. This is L4 direct-native evidence on one Linux
|
|
156
|
+
workstation. The travelling receipt and reproduction are in
|
|
157
|
+
[`scripts/raw-async-delivery/README.md`](./scripts/raw-async-delivery/README.md).
|
|
158
|
+
|
|
159
|
+
This extension rail has no network listener, so the rejected `--ui-server` loopback
|
|
160
|
+
transport's authentication blocker does not apply. The owned product unit then took that
|
|
161
|
+
transport and gave it the obligations a product owes (#82 RAIL 5):
|
|
162
|
+
|
|
163
|
+
- **Artifact.** `run.sh install-copilot-receive` installs the receiver into the user
|
|
164
|
+
extensions directory from an install-state file it owns, refuses a unit it did not
|
|
165
|
+
put there, and removes only what that state names.
|
|
166
|
+
- **Identity.** The extension arms only when the CLI pid's sender marker, the V3 record
|
|
167
|
+
and the SDK's `session.sessionId` all agree; a drifted id or a parent-pid carrier that
|
|
168
|
+
disagrees with the real parent is a refusal, logged, never a best guess.
|
|
169
|
+
- **Liveness.** The marker's owner is the EXTENSION child — the process that actually
|
|
170
|
+
holds the watch — so a crashed receiver stops being deliverable at the next start-key
|
|
171
|
+
read, and the vendor's bootstrap already exits that child when the CLI goes.
|
|
172
|
+
- **Dispatch.** `wakeMode: self-fetch` puts Copilot on the existing mailbox rail. Armed
|
|
173
|
+
and matching → enqueue + doorbell; anything else → `mailbox-undeliverable`.
|
|
174
|
+
- **The flag.** entwurf still does not own the operator's shell and writes nothing to it,
|
|
175
|
+
but it owns ONE invocation: `entwurf copilot` execs the vendor CLI in the caller's own
|
|
176
|
+
terminal with `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` set for that process only,
|
|
177
|
+
and refuses to launch at all unless the receiver unit it is promising is really
|
|
178
|
+
installed. `doctor-copilot-receive` still reads the live CLI environments, because a
|
|
179
|
+
session started any other way without the flag is silently inert. Plain `copilot` is
|
|
180
|
+
untouched; running the owned invocation IS the consent to its profile (EXTENSIONS,
|
|
181
|
+
`--model auto` when no model was given, `--yolo` when no explicit permission or surface
|
|
182
|
+
policy flag was given).
|
|
183
|
+
|
|
184
|
+
The owned receive invocation has now been accepted LIVE (2026-08-23, receipts in the matrix row
|
|
185
|
+
above), which is what moved receive from D0 to D6. Visible fresh is a later, separate LIVE
|
|
186
|
+
(2026-08-25, same row) and does not reopen D3 or D8. What remains owed is still EVIDENCE,
|
|
187
|
+
not code: D3 isolation lost its decisive log to a scratch cleanup and is pending, and the
|
|
188
|
+
active-turn case, `/clear` re-arm and flag durability across vendor releases are
|
|
189
|
+
unmeasured. The hermetic gate drives the real installer and the real extension against a
|
|
190
|
+
stubbed SDK — it proves everything on entwurf's side of the fork and nothing about the
|
|
191
|
+
vendor turn on the other side of it, so a green gate is still not a wake.
|
|
192
|
+
|
|
193
|
+
The hidden `--ui-server` probe remains retired evidence, not a fallback. It found a real
|
|
194
|
+
idle-enqueue capability through an unauthenticated loopback door; the extension finds the
|
|
195
|
+
same class of capability through the CLI-owned stdio lifecycle. Absence of Claude's
|
|
196
|
+
`FileChanged` / `asyncRewake` / `watchPaths` therefore means only that Claude's hook
|
|
197
|
+
mechanism cannot be copied — it never proved Copilot had no vendor wake surface.
|
|
198
|
+
|
|
129
199
|
## Recording a new claim
|
|
130
200
|
|
|
131
201
|
For every matrix change, record:
|
package/README.md
CHANGED
|
@@ -74,13 +74,14 @@ A few words that look unusual for a coding tool.
|
|
|
74
74
|
adapter that hosts the ACP plugin and live control-socket surface, but the base
|
|
75
75
|
install is **not** `pi install npm:...` anymore.
|
|
76
76
|
|
|
77
|
-
The package exposes
|
|
77
|
+
The package exposes six bins:
|
|
78
78
|
|
|
79
79
|
- `entwurf` → `run.sh` (installer, checks, native-bridge doctors/installers)
|
|
80
80
|
- `entwurf-bridge` → the MCP stdio launcher (`mcp/entwurf-bridge/start.sh`)
|
|
81
81
|
- `entwurf-statusline` → the Claude Code statusline renderer (`scripts/meta-bridge-statusline.sh`)
|
|
82
82
|
- `entwurf-agy-statusline` → the Antigravity garden-id statusline renderer (`scripts/agy-statusline.sh`)
|
|
83
83
|
- `entwurf-agy-imprint` → the Antigravity `PreInvocation` birth/sender hook (`scripts/agy-imprint.sh`)
|
|
84
|
+
- `entwurf-copilot-statusline` → the Copilot CLI garden-id footer renderer (`scripts/copilot-statusline.sh`)
|
|
84
85
|
|
|
85
86
|
The bridge/renderers/hook use stable bin names so package upgrades do not bake versioned package-store paths into native-harness settings.
|
|
86
87
|
|
|
@@ -154,7 +155,7 @@ gitignored and may be absent or stale immediately after a checkout or pull.
|
|
|
154
155
|
### Pi adapter / ACP plugin lane
|
|
155
156
|
|
|
156
157
|
To use the `entwurf` provider inside pi, install a compatible pi binary
|
|
157
|
-
separately (`@earendil-works/pi-coding-agent >=0.84.
|
|
158
|
+
separately (`@earendil-works/pi-coding-agent >=0.84.3 <0.85`). Then point pi at
|
|
158
159
|
the npm-installed package or development clone:
|
|
159
160
|
|
|
160
161
|
```bash
|
|
@@ -190,8 +191,58 @@ entwurf install-agy-hooks
|
|
|
190
191
|
entwurf doctor-agy-bridge
|
|
191
192
|
entwurf doctor-agy-statusline
|
|
192
193
|
entwurf doctor-agy-hooks
|
|
194
|
+
|
|
195
|
+
# GitHub Copilot CLI — four independent surfaces, four independent failure modes
|
|
196
|
+
entwurf install-copilot-bridge # birth: garden id + who-sent, on the first prompt
|
|
197
|
+
entwurf install-copilot-mcp # the entwurf tool hand (entwurf_inbox_read lives here)
|
|
198
|
+
entwurf install-copilot-receive # the receiver extension: doorbell + receiver marker
|
|
199
|
+
entwurf install-copilot-statusline # optional for a manual citizen; required for supported fresh
|
|
200
|
+
entwurf doctor-copilot-bridge
|
|
201
|
+
entwurf doctor-copilot-receive
|
|
193
202
|
```
|
|
194
203
|
|
|
204
|
+
#### Launching Copilot as a garden citizen — `entwurf copilot`
|
|
205
|
+
|
|
206
|
+
Copilot only scans for extensions when its CLI is started with
|
|
207
|
+
`COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS`, and when that flag is absent it skips the
|
|
208
|
+
scan **silently** — no error, no log line, no receiver. entwurf does not own your shell
|
|
209
|
+
and writes nothing to your rc files, so it owns one invocation instead:
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
entwurf copilot # managed launch, in this terminal
|
|
213
|
+
entwurf copilot -p "…" --model gpt-5.4
|
|
214
|
+
copilot # the plain vendor CLI, untouched
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
`entwurf copilot` execs the vendor CLI in your current terminal — same cwd, same pid,
|
|
218
|
+
same exit status, no tmux window and no new citizen (a Copilot session is still born on
|
|
219
|
+
its first prompt). Before it launches it verifies that the receiver unit it is about to
|
|
220
|
+
promise is actually installed, and refuses with `entwurf install-copilot-receive` if it
|
|
221
|
+
is not, rather than starting a session that can never be delivered to.
|
|
222
|
+
|
|
223
|
+
**Running it is your consent to its profile.** For that one invocation it adds:
|
|
224
|
+
|
|
225
|
+
| Injected | When |
|
|
226
|
+
|---|---|
|
|
227
|
+
| `COPILOT_CLI_ENABLED_FEATURE_FLAGS=EXTENSIONS` | always — your other feature-flag tokens are preserved, in order, deduplicated |
|
|
228
|
+
| `--model auto` | only when you passed no `--model` |
|
|
229
|
+
| `--yolo` | only when you passed no explicit permission or surface policy flag |
|
|
230
|
+
|
|
231
|
+
The escape hatch is simply to state your own policy: any of `--yolo`, `--allow-all`,
|
|
232
|
+
`--allow-all-tools`, `--allow-all-paths`, `--allow-all-urls`, `--allow-tool`,
|
|
233
|
+
`--deny-tool`, `--allow-url`, `--deny-url`, `--available-tools` or `--excluded-tools`
|
|
234
|
+
suppresses the injected `--yolo`. The narrowing flags are in that list on purpose — adding
|
|
235
|
+
`--yolo` beside your `--allow-url=…` would silently widen exactly what you were
|
|
236
|
+
restricting. `--allow-all-mcp-server-instructions` (prompt content, not authorization) and
|
|
237
|
+
`--autopilot` (a mode) are deliberately not policy flags. Everything you pass is forwarded
|
|
238
|
+
byte-identically, injected defaults land before any `--` terminator, and nothing after the
|
|
239
|
+
terminator is read as policy. Nothing is written to disk; run plain `copilot` and none of
|
|
240
|
+
this applies.
|
|
241
|
+
|
|
242
|
+
Why `--yolo` is the default: the managed lane exists so a sibling can wake an idle session,
|
|
243
|
+
and draining the mailbox with `entwurf_inbox_read` costs two interactive approvals under
|
|
244
|
+
the default permission prompts — which an idle, unattended session is not there to answer.
|
|
245
|
+
|
|
195
246
|
Claude Code uses the supported floor `>=2.1.217`; older versions silently discard the
|
|
196
247
|
exec-hook `args`, so install and doctor fail loud rather than falling back. After any
|
|
197
248
|
upgrade, rerun the installer for the native harness you use and restart its existing
|
|
@@ -427,7 +478,7 @@ A two-pane recording covers the pre-0.12 v1 surface end-to-end — sibling resum
|
|
|
427
478
|
|
|
428
479
|
Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp, origin?, replyable? }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable. A garden-native meta-session carries a trusted `meta-session` envelope, but **`replyable` is a fact its own rail decides, not a consequence of being trusted** — a self-fetch citizen needs a live armed receiver, a native-push citizen needs an alive adapter probe, and a pi session needs its control socket. `entwurf_self` also reports which rail a meta-session reply would ride, because a native-push citizen has no mailbox to name. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling. **v2 never gates on it:** a `wants_reply` from an external/non-replyable caller is passed through and surfaced honestly beside that sender's `replyable: false`, not rejected — the decider routes on target + intent, never on sender replyability. (The retired v1 `entwurf_send` did reject it; that behaviour went with the verb.)
|
|
429
480
|
|
|
430
|
-
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes seven tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi / Claude-Code-meta-mailbox / Antigravity-native-push, and refuses a dormant target instead of waking it. **To open a sibling that does not exist yet use `entwurf_fresh_call`** — it launches one fixed backend (`pi
|
|
481
|
+
In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes seven tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and the explicit/manual `entwurf_register_native` fallback. Native pi exposes the shared capability directly through the extension surface (`entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call` tools; the socket-scan `/entwurf-sessions` command is gone — #50 C4). **For garden-id delivery/reply use `entwurf_v2`** — the canonical surface that classifies the target and routes to live-pi / Claude-Code-meta-mailbox / Antigravity-native-push, and refuses a dormant target instead of waking it. **To open a sibling that does not exist yet use `entwurf_fresh_call`** — it launches one fixed backend (`pi`, `claude-code`, or `copilot`) as a visible window in the operator's own tmux session, requires an explicit model, accepts one optional literal absolute `cwd` (omit it or pass `""` to use the caller's cwd), passes the model and selected directory through the runtime's visible launch path, and hands it a first task; a `copilot` launch goes through entwurf's own managed invocation and is refused before any window opens if this host lacks the Copilot birth, MCP, receiver or visible-footer units. The sibling's first action is a nonce callback whose sender envelope carries its garden id. The launch receipt records the requested model/cwd plus tmux coordinates and never claims that the runtime accepted them or completed delivery. (The v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.) Garden-native operator commands require `--entwurf-control`. There is no spawn target allowlist — the target registry is gone (#50 C3): `entwurf_v2` and `entwurf_resume_call` address an existing record-backed citizen, while `entwurf_fresh_call` takes its explicit backend/model/task and optional cwd directly rather than resolving a model tuple from a registry file. **To reopen a DORMANT pi citizen use `entwurf_resume_call {target}`** — the record supplies transcript, model, provider and cwd, so it takes no prompt, no task and no model override; it runs no turn, returns a LAUNCH receipt and a separate OBSERVATION receipt (only the second says the citizen is back), refuses a non-pi target as `target-not-pi`, and on an unobserved socket leaves the visible window open and releases its lock rather than retrying.
|
|
431
482
|
|
|
432
483
|
### `entwurf_v2` — canonical dispatch verb
|
|
433
484
|
|
|
@@ -446,7 +497,7 @@ In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes sev
|
|
|
446
497
|
|
|
447
498
|
**`entwurf_v2` is the canonical surface for garden-id delivery.** When you have a garden id and want to reach whoever it names — message, reply, or hand-off — `entwurf_v2` is the one surface that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, or native-push Antigravity and routes correctly; *when unsure which transport, use `entwurf_v2`*. This prevents callers from guessing a rail from the shape of an id.
|
|
448
499
|
|
|
449
|
-
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive. It still does **not** mint siblings, and it does not relaunch one either: every row above either reaches a citizen that is already running or refuses. Reopening a dormant pi citizen is `entwurf_resume_call`, a separate lifecycle verb that never routes through this decider. Fresh creation is the separate `entwurf_fresh_call` verb. It opens one fixed Pi
|
|
500
|
+
What v2 provides is a **deterministic dispatch substrate** that moves the "which transport?" decision out of the fallible caller/model and into the decider, with transport-appropriate locking and an honest reject (no `✓ delivered`, no `.msg` garbage) when a target cannot receive. It still does **not** mint siblings, and it does not relaunch one either: every row above either reaches a citizen that is already running or refuses. Reopening a dormant pi citizen is `entwurf_resume_call`, a separate lifecycle verb that never routes through this decider. Fresh creation is the separate `entwurf_fresh_call` verb. It opens one fixed Pi, Claude Code, or Copilot runtime visibly in the caller's tmux session with a required explicit model passed in that runtime's measured CLI dialect and one optional literal absolute `cwd`; omitted or `""` means the caller's cwd. Copilot opens through `entwurf copilot`, never the bare vendor. It returns only a synchronous launch receipt and lets the sibling report its new address asynchronously through the sender envelope of a nonce callback. Use this cwd input for a new cross-repository sibling; do not resume a dormant citizen as a cwd substitute. The meta-mailbox row requires an **active** self-fetch receiver; native-push requires a record-backed, probe-alive native conversation and never borrows mailbox state. The [mux launch lane](./docs/mux-launch-rail.md) owns placement, fixed-runtime launch, and the two narrow compositions above it (fresh-call and resume-call placement); delivery does not import launch, and mux is not a delivery transport.
|
|
450
501
|
|
|
451
502
|
A live pi target is *reached* over its control socket, but the socket is dispatch-internal transport, never identity (#50 C4). A control socket that no meta-record claims — a pre-record-era resident, an unreadable store, or a stale/planted file — is refused for **every** intent as `record-less-socket`, and the reject names the fix (restart the resident so `session_start` births its record, or quiesce and run the fresh-cut). `entwurf_peers` reports the same state as an aggregated `record-less-socket` diagnostic rather than a peer row.
|
|
452
503
|
|
package/VERIFY.md
CHANGED
|
@@ -43,24 +43,24 @@ Verification here is not a benchmark. In production we exchange short turns and
|
|
|
43
43
|
- **Deterministic floor — two tiers (#70):** `pnpm check` is the everyday CORE — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the FULL deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the frozen-candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT — this document records meaning and principles, not the command list); a gate changes tier by semantic-class decision, never by getting faster or slower. Both tiers exclude the separately scheduled `check-gate-qualification`.
|
|
44
44
|
- **Discriminating power of that floor:** `./run.sh check-gate-qualification` (scheduled, not ambient: standalone when a lane changes a gate/mutant/matrix, in the CI `check` job on every push, and as a release-gate MUST step — no longer inside the default check chains) re-plants committed defect mutants (`scripts/mutants/*.json`, one per closed defect class) in an isolated snapshot repo and requires each to turn its gate red **bounded and at its claimed `[QK:<claim>]` signature** — a wrong-reason red fails, a baseline-red control voids the whole group, and the runner is negative-controlled on every run (zero-match/multi-match/survived/wrong-reason/hang/control-red/impurity). This measures whether the deterministic gates still *block* what they claim to block; it is **not a new evidence level** (L0–L5 are untouched) and never substitutes for LIVE evidence. Per-cut records cite claim IDs + killed mutant IDs — "N checks passed" alone is not evidence. `check-agy-permission-matrix` complements it with the enumerated permission contract space (literal cells + stated exclusion rules, oracle independent of the SUT).
|
|
45
45
|
- **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir> --cut` — `pnpm run check:full` + the v2-native live gates + the ACP plugin acceptance floor. It reports a **two-tier summary**:
|
|
46
|
-
- **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm run check:full`, `check-gate-qualification`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send), the axis wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-claude-native-resume-live`), and `smoke-entwurf-chain-live` — the cross-harness delivery chain (native Claude Code → pi GPT → pi ACP Sonnet → mailbox terminus) proving sender identity and replyability at every hop plus a real read receipt at the end. (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
|
|
46
|
+
- **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm run check:full`, `check-gate-qualification`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, `doctor-pi-provider` (#81 — `check-bridge` proves the launcher this checkout SHIPS; this proves the invocation the operator's pi provider actually EXECS, by booting it and requiring the entwurf verb set back, because `command -v` answers yes for a command that exits 127; wired as a step on 2026-08-19 after a relocated pnpm cmd-shim cost a cut sixteen LIVE steps before the same fact surfaced at `smoke-acp-bundled-mcp-live`), the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send), the axis wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-claude-native-resume-live`), and `smoke-entwurf-chain-live` — the cross-harness delivery chain (native Claude Code → pi GPT → pi ACP Sonnet → mailbox terminus) proving sender identity and replyability at every hop plus a real read receipt at the end. (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
|
|
47
47
|
- **BEHAVIOR tier** (advisory, non-blocking): the resident-garden-guard positive (a model-in-loop `entwurf_self` turn). A BEHAVIOR FAIL is surfaced with its artifact path but **never blocks the cut**. The lane holds what the model *chooses*, never what our wiring fails to deliver — a gate that TELLS the model which tool to call stays MUST, because its failure is ours — measured 2026-07-24, when the tool turned out to be absent from the session schema in both observed failures (the bundled-MCP readiness gap recorded in `scripts/smoke-acp-v2-send-live.ts`).
|
|
48
48
|
- **Every MUST step is invoked and reports its own outcome.** Prerequisite-bearing LIVE MUST steps ride the P1 STEP OUTCOME protocol (`scripts/lib/step-outcome.sh`): exit 0 = PASS, exit 97 = SKIP (a prerequisite the step does not have, printed as an `[entwurf:skip]` line), anything else = FAIL. The two non-skippable static steps (`pnpm run check:full`, `check-gate-qualification`) are inline: 0 = PASS, nonzero = FAIL, no SKIP arm — they have no prerequisite to decline. A skip is never counted as a pass — that hole is what let a cortex-less host read as cortex acceptance. Without `--cut` this is the unattended diagnostic: SKIPs are reported and the run still exits 0. **`--cut` makes it acceptance and any MUST SKIP is red**, which is how "a real cut needs `LIVE=1` with `SKIP=0`" stopped being prose. A green MUST gate is **necessary, not sufficient** — GLG authorizes the cut.
|
|
49
49
|
- **When cost-bearing MUST gates run (fixed 2026-07-23, the F6/F7 lesson):** a commit that touches a rail a MUST-tier live gate covers runs that gate **before cross-review is requested** — never parked behind "run it at approval time". Deferring a wired gate to a human decision is what let F6/F7 ship reviewed-and-approved; the wiring exists so the verdict never depends on who pressed enter. "배선이 없어 못 한 것은 OK, 배선이 있는데 안 돌린 것은 우리가 남긴 구멍이다." Model-in-loop cost is spent via the subscription-backed `entwurf` provider where the gate allows it, a free-tier native model otherwise; cost is a reason to pick the cheap target, not to skip the gate.
|
|
50
50
|
|
|
51
|
-
> **Cortex is an on-demand axis, not an aggregate one.** Its rail needs an external Snowflake connection and login that the host owns, not the repo — so wiring it into the aggregate would block every cut taken on a host without that account. **The release aggregate does not re-certify Cortex**; `LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live` stays a required direct call whenever a cut changes Cortex rail code or an operator elects to certify that host. Its honest-skip behaviour is unchanged: run it without the connection and it reports protocol SKIP, never a pass.
|
|
51
|
+
> **Cortex is an on-demand axis, not an aggregate one.** Its rail needs an external Snowflake connection and login that the host owns, not the repo — so wiring it into the aggregate would block every cut taken on a host without that account. **The release aggregate does not re-certify Cortex**; `LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live` stays a required direct call whenever a cut changes Cortex rail code or an operator elects to certify that host. Its honest-skip behaviour is unchanged: run it without the connection and it reports protocol SKIP, never a pass. **Operator-host limit (2026-08-20, measured):** the source-owning host has no Snowflake subscription, and Cortex Code offers no free tier that a live turn can reach — a direct attempt confirmed it. So on this host `smoke-acp-cortex-live` can only ever report protocol SKIP, and no LIVE Cortex evidence can be produced here until Snowflake supplies a free-usable route or the account is subscribed. Record that SKIP as an absent axis; never soften it into a pass, and never substitute a different backend as Cortex evidence.
|
|
52
52
|
>
|
|
53
53
|
> A cut that touches the prompt-lifecycle contract (no wall clock on a running turn) owes one long-turn acceptance the aggregate floor is too short to carry: `LIVE=1 ./run.sh smoke-acp-long-turn-live` drives a real turn whose tool work outlasts the retired 600s cutoff and requires exactly one cold ACP bootstrap in the transcript. It takes >12 minutes by construction and is on-demand, not part of `release-gate`.
|
|
54
54
|
>
|
|
55
|
-
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-5.6-
|
|
55
|
+
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-5.6-luna` and recorded-ACP `entwurf/claude-sonnet-5`, the only shape that re-injects a bridge extension), and the Claude Code cell ends where its capability ends: its resume is refused as `target-not-pi` with no window opened and no lock residue (the per-gid coordination lock is released).
|
|
56
56
|
>
|
|
57
57
|
> One cell cannot be fully fenced, and that is recorded rather than glossed: the recorded-ACP pi cell runs under the operator's REAL home, because its provider spawns `claude` as a child that authenticates from there — measured, a fenced HOME kills that turn with `Authentication required` before the model is ever reached, and `CLAUDE_CONFIG_DIR` alone does not fix it. That is the same trade `smoke-acp-bundled-mcp-live` already makes. While that cell runs, its citizen's control socket and per-gid lock exist under the operator's own `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks`; its meta store stays fixture, so no garden record is minted outside the fixture, and the run ends by proving all six real roots hold the entry sets they started with, with no fixture garden id and no leftover lock.
|
|
58
58
|
>
|
|
59
59
|
> Be honest about its cost, because it is a MUST: it spends real model turns on the operator's configured runtimes (two pi siblings, each resumed once, plus one Claude Code sibling), it READS the operator's real runtime config, and the siblings' native session transcripts stay in the real pi agent dir — they are not cleaned up, and they are part of the evidence a resume was real. The fence is per-axis rather than absolute: the four meta roots (records, mailbox, receivers, senders) are fixture for every cell, so no garden record is ever minted outside it; the native pi cell's control socket and v2 lock are fixture too; the ACP pi cell's are REAL and transient (see the paragraph above); and the Claude cell runs its runtime under the real HOME while its mailbox and meta stay fixture. The run ends by proving the operator's SIX real roots — the four meta roots plus `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks` — hold the entry sets they started with, with no fixture garden id anywhere, and that proof now runs on the failure path as well as the green one. Missing prerequisites decline with the protocol SKIP (97), which `release-gate --cut` refuses rather than rounding up.
|
|
60
60
|
>
|
|
61
|
-
> **Fresh-call LIVE is on-demand, not part of `release-gate`.** `LIVE=1 ./run.sh smoke-mux-fresh-call-live` opens configured Pi and Claude Code siblings, spends two model turns, and preserves their native transcripts; run it directly whenever a cut changes mux fresh-call/launch behavior. Its private tmux servers and fixture-bound entwurf write axes make it deterministic about garden-record/socket residue, but those real native turns should not appear unexpectedly in every aggregate cut.
|
|
61
|
+
> **Fresh-call LIVE is on-demand, not part of `release-gate`.** `LIVE=1 ./run.sh smoke-mux-fresh-call-live` opens configured Pi and Claude Code siblings, spends two model turns, and preserves their native transcripts; run it directly whenever a cut changes mux fresh-call/launch behavior. Its private tmux servers and fixture-bound entwurf write axes make it deterministic about garden-record/socket residue, but those real native turns should not appear unexpectedly in every aggregate cut. **Both this smoke and `smoke-mux-lifecycle-live` enumerate `pi` and `claude-code` only — that exclusion is intentional.** A Copilot visible-fresh (step 9 clause 7) was accepted on 2026-08-25 as an operator-metered LIVE (receipts in `DELIVERY.md`'s Copilot matrix row and the issue #82 thread). It still spends Copilot premium quota, still needs its own grant to re-run, and is never folded into those loops or into the release-gate MUST tier.
|
|
62
62
|
>
|
|
63
|
-
> The aggregate release gate does not own a live agy conversation id, so agy's real native-push round trip is a separate acceptance axis: three fail-loud doctors plus `LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live`, followed by a fresh-conversation sender/reply check after package install. Its deterministic install/sender gates are already inside `pnpm run check:full`; do not misreport the aggregate gate as live agy evidence.
|
|
63
|
+
> The aggregate release gate does not own a live agy conversation id, so agy's real native-push round trip is a separate acceptance axis: three fail-loud doctors plus `LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live`, followed by a fresh-conversation sender/reply check after package install. Its deterministic install/sender gates are already inside `pnpm run check:full`; do not misreport the aggregate gate as live agy evidence. **Cost fence:** the agy conversation this smoke drives runs on a free account, so open it on `gemini-3.6-flash` — never a Pro tier. The model is the operator's choice at conversation-open time; entwurf never selects it, and no assertion reads it (see the shipped-lane note: model display is not part of the agy contract).
|
|
64
64
|
>
|
|
65
65
|
> Authoritative per-cut counts and digests live in BASELINE/CHANGELOG, not inline
|
|
66
66
|
> here; embedding them in the protocol makes a correct guide stale after every cut.
|
|
@@ -146,7 +146,7 @@ git clone https://github.com/junghan0611/entwurf /path/to/entwurf && cd $_
|
|
|
146
146
|
# re-run the SAME command any time to repair a broken install
|
|
147
147
|
```
|
|
148
148
|
|
|
149
|
-
Expected tail: `DONE: entwurf setup (pi adapter + detected native bridges + v2 install smoke) green.` On a host with `claude`, verify `./run.sh doctor-meta-bridge`. On a host with `agy`, verify all three: `doctor-agy-bridge`, `doctor-agy-statusline`, and `doctor-agy-hooks`. Setup keeps optional-harness failures non-fatal so pi/Claude hosts are not bricked; the doctors are the fail-loud acceptance surface.
|
|
149
|
+
Expected tail: `DONE: entwurf setup (pi adapter + detected native bridges + v2 install smoke) green.` On a host with `claude`, verify `./run.sh doctor-meta-bridge`. On a host with `agy`, verify all three: `doctor-agy-bridge`, `doctor-agy-statusline`, and `doctor-agy-hooks`. After adding a backend to `META_BACKENDS`, re-run the sibling install then the doctor — a green checkout with a stale deployed plugin is a silent write-stop on that rail. Setup keeps optional-harness failures non-fatal so pi/Claude hosts are not bricked; the doctors are the fail-loud acceptance surface.
|
|
150
150
|
|
|
151
151
|
The wiring / meta-bridge / smoke steps are internal building blocks of `setup` (`install_local_package`, `scripts/meta-bridge-install.sh`, `validate_entwurf_bridge`) — call `setup`, never the parts. Consumers who `npm install @junghanacs/entwurf` get the obvious npm surface; that path is not the developer concern here.
|
|
152
152
|
|
package/demo/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
> **Archived pre-0.12 evidence.** These scripts still describe the retired v1 `entwurf` / `entwurf_resume` / `entwurf_send` demo flow. They are kept for historical comparison and will be replaced by a v2-native retake in a post-0.12 follow-up; do not treat them as the current 0.12 runnable recipe.
|
|
4
4
|
|
|
5
|
+
> **Model ids here are archived, not recommended (2026-08-20).** The `entwurf/gpt-5.4` rows below record what these GIFs actually ran on. They are stale twice over: `entwurf/gpt-5.4` is no longer a curated `entwurf` ACP id at all — that provider serves only the `claude-*` and `cortex-*` rows in `pi-extensions/lib/acp/models.ts` — and the live-spend default has since moved to `openai-codex/gpt-5.6-luna` under a cheaper plan. Read them as a record of the recording, never as a default to copy; the current defaults live in `VERIFY.md` and `NEXT.md`.
|
|
6
|
+
|
|
5
7
|
Two recorded GIF scripts live here. Both use `asciinema` for capture and
|
|
6
8
|
`agg` for cast → GIF conversion. Both share the same gitignore policy
|
|
7
9
|
(`*.cast` global, `demo/*.gif`, `demo/*.log` — only the `.sh` and this
|
|
@@ -137,7 +139,7 @@ SCENE_DELAY=30 FINAL_PAUSE=10 bash demo.sh
|
|
|
137
139
|
|
|
138
140
|
## Prerequisites
|
|
139
141
|
|
|
140
|
-
- `pi` on PATH (current floor 0.84.
|
|
142
|
+
- `pi` on PATH (current floor 0.84.3)
|
|
141
143
|
- `entwurf` provider configured + auth ready for the selected sender/peer models
|
|
142
144
|
- `asciinema` installed
|
|
143
145
|
- `agg` installed (optional — only for GIF conversion)
|
package/demo/demo-baseline.sh
CHANGED
|
@@ -7,6 +7,17 @@
|
|
|
7
7
|
# 2. Entwurf surface — spawn a sibling via the entwurf tool and receive its
|
|
8
8
|
# reply in the same pane (cross-model, mode=sync).
|
|
9
9
|
#
|
|
10
|
+
# ARCHIVED pre-0.12 evidence — NOT a runnable recipe. Scene 2 drives the retired
|
|
11
|
+
# v1 `entwurf` verb, which the 0.12 cutover removed. Kept for historical
|
|
12
|
+
# comparison only. See demo/README.md.
|
|
13
|
+
#
|
|
14
|
+
# MODEL NOTE (2026-08-20). The model ids below are the ARCHIVED values these
|
|
15
|
+
# recordings actually used — they are kept as the historical record, not as a
|
|
16
|
+
# recommendation. Two things are stale about them: `entwurf/gpt-5.4` is no
|
|
17
|
+
# longer a curated `entwurf` ACP id at all (that provider serves only the
|
|
18
|
+
# claude-* and cortex-* rows in pi-extensions/lib/acp/models.ts), and GLG's
|
|
19
|
+
# live-spend default moved to `openai-codex/gpt-5.6-luna` on a Plus plan. Do
|
|
20
|
+
# NOT copy these ids into a live harness default — see VERIFY.md and NEXT.md.
|
|
10
21
|
# Layout (tmux, 220x50):
|
|
11
22
|
# pane 0 (single) — driven pi (claude-sonnet-5) — receives both prompts.
|
|
12
23
|
#
|
|
@@ -32,7 +43,7 @@ DRIVER_LOG="$OUTDIR/baseline-debug.log"
|
|
|
32
43
|
# Driven pi runs the bridge surface and answers both prompts.
|
|
33
44
|
DRIVER_MODEL=${DRIVER_MODEL:-entwurf/claude-sonnet-5} # pias
|
|
34
45
|
# Sibling spawned via entwurf in scene 2 — different backend for contrast.
|
|
35
|
-
SIBLING_MODEL=${SIBLING_MODEL:-entwurf/gpt-5.4} # piat
|
|
46
|
+
SIBLING_MODEL=${SIBLING_MODEL:-entwurf/gpt-5.4} # piat — ARCHIVED id, see MODEL NOTE above
|
|
36
47
|
SIBLING_CWD=${SIBLING_CWD:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}
|
|
37
48
|
|
|
38
49
|
# Pacing in seconds.
|
package/demo/demo.sh
CHANGED
|
@@ -7,6 +7,14 @@
|
|
|
7
7
|
# See demo/README.md. Scene 3's delivery proof was recovered as a deterministic gate
|
|
8
8
|
# (scripts/check-bridge-delivery.ts); the v2-native retake is a post-0.12 follow-up.
|
|
9
9
|
#
|
|
10
|
+
#
|
|
11
|
+
# MODEL NOTE (2026-08-20). The model ids below are the ARCHIVED values these
|
|
12
|
+
# recordings actually used — they are kept as the historical record, not as a
|
|
13
|
+
# recommendation. Two things are stale about them: `entwurf/gpt-5.4` is no
|
|
14
|
+
# longer a curated `entwurf` ACP id at all (that provider serves only the
|
|
15
|
+
# claude-* and cortex-* rows in pi-extensions/lib/acp/models.ts), and GLG's
|
|
16
|
+
# live-spend default moved to `openai-codex/gpt-5.6-luna` on a Plus plan. Do
|
|
17
|
+
# NOT copy these ids into a live harness default — see VERIFY.md and NEXT.md.
|
|
10
18
|
# Layout (tmux, 220x50):
|
|
11
19
|
# pane 0 (top) — peer pi (codex, gpt-5.4) — idle, waits for greeting
|
|
12
20
|
# pane 1 (bottom) — sender pi (claude-sonnet-5) — driven by send-keys
|
|
@@ -37,7 +45,7 @@ PEER_LOG="$OUTDIR/peer-debug.log"
|
|
|
37
45
|
SENDER_LOG="$OUTDIR/sender-debug.log"
|
|
38
46
|
|
|
39
47
|
# Models match the user's piat / pias aliases.
|
|
40
|
-
PEER_MODEL=${PEER_MODEL:-entwurf/gpt-5.4} # piat
|
|
48
|
+
PEER_MODEL=${PEER_MODEL:-entwurf/gpt-5.4} # piat — ARCHIVED id, see MODEL NOTE above
|
|
41
49
|
SENDER_MODEL=${SENDER_MODEL:-entwurf/claude-sonnet-5} # pias
|
|
42
50
|
|
|
43
51
|
# Pacing in seconds. Tuned from real runs: each scene's actual agent work
|