@junghanacs/entwurf 0.12.8 → 0.12.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (96) hide show
  1. package/AGENTS.md +134 -248
  2. package/BASELINE.md +1 -1
  3. package/CHANGELOG.md +39 -1
  4. package/DELIVERY.md +5 -4
  5. package/README.md +148 -23
  6. package/VERIFY.md +3 -2
  7. package/demo/README.md +2 -2
  8. package/demo/demo.sh +7 -1
  9. package/docs/setup-clean-host.md +24 -7
  10. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +168 -81
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +12 -12
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +5 -3
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +16 -18
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +14 -13
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +11 -3
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +15 -4
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +500 -54
  26. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +8 -3
  27. package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +14 -2
  28. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +155 -29
  29. package/mcp/entwurf-bridge/src/index.ts +200 -94
  30. package/package.json +11 -9
  31. package/pi-extensions/entwurf-control.ts +81 -39
  32. package/pi-extensions/lib/acp/models.ts +12 -12
  33. package/pi-extensions/lib/acp/overlay.ts +5 -3
  34. package/pi-extensions/lib/entwurf-core.ts +26 -9
  35. package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
  36. package/pi-extensions/lib/entwurf-fact-provider.ts +24 -19
  37. package/pi-extensions/lib/entwurf-facts.ts +13 -13
  38. package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
  39. package/pi-extensions/lib/entwurf-self-address.ts +8 -9
  40. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
  41. package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
  42. package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
  43. package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
  44. package/pi-extensions/lib/entwurf-v2-production.ts +22 -13
  45. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +11 -3
  46. package/pi-extensions/lib/meta-sender-identity.ts +15 -5
  47. package/pi-extensions/lib/meta-session.ts +543 -58
  48. package/pi-extensions/meta-bridge-hook.ts +8 -2
  49. package/run.sh +78 -67
  50. package/scripts/agy-bridge-config.py +249 -49
  51. package/scripts/agy-bridge.sh +59 -14
  52. package/scripts/agy-imprint.ts +15 -1
  53. package/scripts/check-acp-carrier-augment.ts +34 -2
  54. package/scripts/check-acp-sdk-surface.ts +22 -11
  55. package/scripts/check-acp-session-reuse.ts +1 -1
  56. package/scripts/check-acp-session-store.ts +3 -3
  57. package/scripts/check-agy-permission-matrix.py +655 -0
  58. package/scripts/check-agy-sender-identity.ts +83 -0
  59. package/scripts/check-entwurf-control-rpc.ts +2 -2
  60. package/scripts/check-entwurf-deliverability.ts +9 -6
  61. package/scripts/check-entwurf-fact-provider.ts +16 -8
  62. package/scripts/check-entwurf-facts.ts +13 -13
  63. package/scripts/check-entwurf-resume-args.ts +25 -63
  64. package/scripts/check-entwurf-self-address.ts +187 -4
  65. package/scripts/check-entwurf-session-identity.ts +7 -6
  66. package/scripts/check-entwurf-v2-contract.ts +2 -2
  67. package/scripts/check-entwurf-v2-production.ts +9 -7
  68. package/scripts/check-entwurf-v2-spawn-production.ts +8 -4
  69. package/scripts/check-entwurf-v2-surface.ts +327 -14
  70. package/scripts/check-fresh-cut-gate.sh +305 -4
  71. package/scripts/check-gate-qualification.ts +785 -0
  72. package/scripts/check-meta-identity-consumers.ts +501 -1
  73. package/scripts/check-meta-listing.ts +91 -9
  74. package/scripts/check-meta-receiver-marker.ts +54 -0
  75. package/scripts/check-model-lock.ts +1 -1
  76. package/scripts/check-shell-quote.ts +2 -1
  77. package/scripts/lib/mutation-qualify.ts +794 -0
  78. package/scripts/meta-bridge-fresh-cut.ts +164 -28
  79. package/scripts/mutants/acp-augment.json +30 -0
  80. package/scripts/mutants/agy-permission.json +144 -0
  81. package/scripts/mutants/meta-identity.json +17 -0
  82. package/scripts/mutants/self-address.json +59 -0
  83. package/scripts/mutants/v2-surface.json +87 -0
  84. package/scripts/pi_settings_io.py +65 -0
  85. package/scripts/register-pi-package.py +183 -37
  86. package/scripts/register-pi-provider.py +68 -10
  87. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  88. package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
  89. package/scripts/smoke-acp-v2-send-live.ts +33 -18
  90. package/scripts/smoke-agy-install-state.sh +205 -20
  91. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
  92. package/scripts/smoke-meta-install-state.sh +1 -1
  93. package/scripts/smoke-pi-attach.ts +7 -2
  94. package/scripts/smoke-user-scope-citizen.sh +177 -0
  95. package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
  96. package/scripts/check-entwurf-mailbox-guard.ts +0 -262
package/CHANGELOG.md CHANGED
@@ -4,6 +4,44 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.12.10 — 2026-07-27
8
+
9
+ ### Changed
10
+
11
+ - **The Claude ACP dependency rail moves to `@agentclientprotocol/claude-agent-acp` 0.62.0.** The paired SDK surface fence now covers Claude Agent SDK 0.3.219; this is a dependency refresh, not a claim that MCP readiness timing changed.
12
+ - **The ACP rail document now names its unresolved readiness question precisely.** The ordered probe records wire availability, `newSession`, model enforcement, and prompt boundaries before any adapter remedy or Cortex work is considered.
13
+ - **Gate qualification is part of the deterministic floor.** Committed defect mutants run in an isolated snapshot and must fail their named `[QK:<claim>]` oracle; the agy permission contract is likewise covered by an independent literal matrix.
14
+
15
+ ### Fixed
16
+
17
+ - **All citizen rails now share the same record authority without inventing pi privilege.** Control-socket, self-fetch, and native-push capability differences remain explicit while stale pi-special address and transport prose is removed.
18
+ - **The shipped pi and MCP tool descriptions tell the complete v2 dispatch truth.** Native-push direct injection, its three-valued probe rejects, mailbox deliverability, control-socket lock scope, and spawn-bg's separate relaunch transport are described and regression-fenced on both surfaces.
19
+ - **Native-push self-awareness and agy permissions follow their actual rail.** Native-push never advertises an inbox; normal-path agy approval covers `entwurf_v2`, `entwurf_peers`, and `entwurf_self` with per-rule ownership, strict state migration, and separate runtime/ownership doctor verdicts.
20
+
21
+ ### Verification
22
+
23
+ - Pre-version landing HEAD `9a501b30f0e7d82307d885f1a1eb9d91c79c5f16` passed exact-SHA GitHub Actions run [30252596435](https://github.com/junghan0611/entwurf/actions/runs/30252596435): `check`, `install-surface`, and `artifact-consumer` all success.
24
+ - The prepared tree passed `pnpm check`; `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.12.10.d4gC9v` completed all green: **MUST PASS=17 FAIL=0 SKIP=0** and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Full log: `/tmp/entwurf-release-gate-0.12.10.d4gC9v/release-gate.log`; per-step artifacts are preserved in that log. Prepared-HEAD exact-SHA CI and preserved-candidate acceptance remain deliberately deferred to `make`.
25
+
26
+ ## 0.12.9 — 2026-07-26
27
+
28
+ ### Changed
29
+
30
+ - **The curated ACP surface adopts Claude Opus 5 on pi 0.82.1.** The deliberately narrow two-model surface keeps Sonnet 5 and replaces the Opus 4.8 anchor with Opus 5 (1M context, 128K max output, reasoning enabled). The pi runtime pin, closed peer range, lockfile, install gates, and current-version docs move together; source review of pi 0.82.1 confirmed the extension-loader aliases and `/compat` catalog seam are unchanged.
31
+ - **`meta-bridge-fresh-cut` now reports the transition that actually occurred.** Exit 0 means the cut completed, 1 means nothing moved, 2 is usage, 3 means the cut transition is incomplete, and 4 means the generation was archived and the fresh v3 store opened but residue cleanup is incomplete. The command help, `run.sh` usage, operator docs, and deterministic decision/source-fence cells carry the same contract; exit 4 may proceed to `setup`, while rerunning after a new citizen is born would archive the new generation too.
32
+
33
+ ### Fixed
34
+
35
+ - **A marker that cannot plausibly own a session no longer blocks the only repair verb or grants identity indefinitely.** The Claude hook, agy imprint, marker write boundary, all sender/receiver readers, fresh-cut inspection, and sender-candidate filtering share one `isPlausibleOwnerPid` policy. On the currently certified Linux desktop/workstation axis, pid 1 is refuted by construction and reported separately from a proven-dead owner; the cut clears that residue instead of waiting forever on init. A container running the harness as pid 1 remains unsupported and fails closed rather than quietly widening the evidence boundary.
36
+ - **`setup` preserves the repository's tracked pi settings across the full install path.** Both writers of `.pi/settings.json` now share one serializer, recognize the portable relative package entry as the same checkout, and leave already-satisfied bytes untouched. The end-to-end gate plants the candidate-index settings in a stand-in checkout, drives the real `run.sh install`, and requires byte and mtime identity, covering both writers and user-scope side effects rather than only a helper.
37
+ - **Duplicate `nativeSessionId` claims are quarantined on discovery and refused wherever a record becomes an address.** `entwurf_peers` lists neither rival while preserving unrelated citizens and naming diagnostics; canonical `entwurf_v2` dispatch checks the store before choosing any transport, and dormant pi resume uses the same addressable read. A regular unreadable rival fails loud because it might be the duplicate, while symlinked, drifted, or unparseable neighbours remain certification/listing defects without being promoted into addressable rivals. The deliberately narrower raw mailbox and marker paths retain the per-entry half of the contract; that boundary and its promotion rule remain tracked in #55.
38
+ - **Record bytes now come from the same opened file description that proves their kind.** `readStoreRecordFile` opens with `O_NOFOLLOW` so a final-component regular-to-symlink swap fails before a byte is read, uses `fstat` on that fd, reads through the fd, and closes in a `finally`. `O_NONBLOCK` prevents the fd-classification repair from introducing a FIFO hang. The preceding `lstat` classification remains a separate policy layer so settled sockets, devices, and mode-000 directories receive the certification contract's non-regular verdict instead of leaking `ENXIO`/`EACCES` as a second vocabulary.
39
+
40
+ ### Verification
41
+
42
+ - Pre-version landing HEAD `aaab00fbd293300d25c294580bb19bd3a88ad757` passed exact-SHA GitHub Actions run [30186472796](https://github.com/junghan0611/entwurf/actions/runs/30186472796): `check`, `install-surface`, and `artifact-consumer` all success.
43
+ - The prepared tree passed an independent `pnpm check`, then `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.12.9.8NSzz7` completed all green: **MUST PASS=17 FAIL=0 SKIP=0** and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0. Full log: `/tmp/entwurf-release-gate-0.12.9.8NSzz7/release-gate.log`; per-step artifact paths are preserved inside it. Prepared-HEAD exact-SHA CI and preserved-candidate acceptance remain deliberately deferred to `make`.
44
+
7
45
  ## 0.12.8 — 2026-07-25
8
46
 
9
47
  ### Changed
@@ -30,7 +68,7 @@ All notable changes to this project will be documented here. Format follows [Kee
30
68
  - Pre-version landing HEAD `1345688001ed6629bd0f58996a36134e7b7874bc` passed exact-SHA GitHub Actions run [30150824225](https://github.com/junghan0611/entwurf/actions/runs/30150824225): `check`, `install-surface`, and `artifact-consumer` all success.
31
69
  - Published `0.12.8-repair.1` passed installed `doctor-meta-bridge` on maintainer + secondary Linux hosts after a new real Claude session opened with a live MCP child; both runs included physical `entwurf_v2` delivery and live owner join (BASELINE HISTORY).
32
70
  - On the stable prepared tree, `LIVE=1 ./run.sh release-gate` is all green — **MUST PASS=17 FAIL=0 SKIP=0** (its first step is the full `pnpm check`; the run includes `smoke-acp-bundled-mcp-live` and `smoke-acp-v2-send-live`) and **BEHAVIOR PASS=1 FAIL=0**, EXIT=0 — at scratch `/tmp/entwurf-release-gate-0.12.8.u9y9IX`, complete log `/tmp/entwurf-release-gate-0.12.8.u9y9IX/release-gate.log`, per-step artifact paths printed inside it. The static gate judges the **candidate index**, so the release-prep bytes were staged before the run, not merely present in the working tree.
33
- - The prepared-HEAD exact-SHA CI, the preserved candidate and its container acceptance, the tag, the GitHub release, and `latest` publication remain deliberately deferred to `make` / `publish`.
71
+ - Prepared HEAD `e31c28f` passed exact-SHA GitHub Actions run [30152323861](https://github.com/junghan0611/entwurf/actions/runs/30152323861) with `check`, `install-surface`, and `artifact-consumer` all successful. The preserved candidate `junghanacs-entwurf-0.12.8.tgz` (sha256 `7c7e8985823391ec6dfae918e08c4aed1fafd06b7415806b2d591b0cb95891f3`) passed the checkout-invisible container consumer, was tagged as `v0.12.8`, released on GitHub, and published as `latest=0.12.8` while `repair=0.12.8-repair.1` remained unchanged.
34
72
 
35
73
  ## 0.12.8-repair.1 — 2026-07-22
36
74
 
package/DELIVERY.md CHANGED
@@ -86,7 +86,7 @@ D2 receiver_armed: pass
86
86
  D3 addressed_enqueue: pass
87
87
  D4 idle_active_wake: pass
88
88
  D5 context_injection: pass token=AGY-PARITY-3399
89
- D6 continuity: pass session_id=<native-id> model=claude-opus-4-8
89
+ D6 continuity: pass session_id=<native-id> model=claude-opus-5
90
90
  D7 completion_reply: partial reason="no garden outbox yet"
91
91
  D8 robustness: partial reason="loop guard present; crash recovery not tested"
92
92
  ```
@@ -213,11 +213,12 @@ three markers) but **not** simultaneous model invocation by two conversations
213
213
  under one agy pid: one marker file would be last-writer-wins, so that concurrency
214
214
  is explicitly unsupported.
215
215
 
216
- Current deterministic floor: `smoke-agy-install-state` 140 checks,
216
+ Current deterministic floor: `smoke-agy-install-state` 167 checks,
217
217
  `smoke-agy-statusline-state` 69, `smoke-agy-hooks-state` 44,
218
218
  `check-agy-sender-identity` 28, plus the shared self-address/native-push gates.
219
- The bridge installer owns only `mcp(entwurf-bridge/entwurf_v2)` in
220
- `permissions.allow`; broad YOLO policy stays operator-owned. Live 2026-07-13
219
+ The bridge installer owns one narrow rule per normal-path tool
220
+ (`entwurf_v2`, `entwurf_peers`, `entwurf_self`) in `permissions.allow`;
221
+ broad YOLO policy stays operator-owned. Live 2026-07-13
221
222
  (agy 1.0.x): automatic birth → gid/statusline → record-backed sender → sibling
222
223
  delivery → same-gid native-push reply passed. Live 2026-07-14 (**agy 1.1.0**):
223
224
  re-verified on the new minor — `entwurf_self` answered without a permission
package/README.md CHANGED
@@ -159,7 +159,7 @@ because Node refuses to strip `.ts` files under `node_modules`.
159
159
  ### Pi adapter / ACP plugin lane
160
160
 
161
161
  To use the `entwurf` provider inside pi, install a compatible pi binary
162
- separately (`@earendil-works/pi-coding-agent >=0.82.0 <0.83`). Then point pi at
162
+ separately (`@earendil-works/pi-coding-agent >=0.82.1 <0.83`). Then point pi at
163
163
  the npm-installed package or development clone:
164
164
 
165
165
  ```bash
@@ -261,15 +261,82 @@ Only that accepted file may be published under the explicitly authorized lane:
261
261
  > there is nothing to diagnose or branch on.
262
262
  >
263
263
  > Note the deliberate scope, stated as it actually is. A **store-wide** scan runs on
264
- > **identity writes** and in the doctor not on every mailbox poke; a call-relay does
265
- > not re-scan the whole store per message. What every **targeted read** does hold is
266
- > the per-entry half of the same contract: `readMetaIdentityByGardenId` refuses a
267
- > record that is not a regular file (a symlink is never followed, in *either*
268
- > direction) and one whose body disagrees with its name, naming the verb. What it
269
- > does **not** do is prove store-wide uniqueness on the read path, so on a store that
270
- > would fail certification two records can still claim one `nativeSessionId` and
271
- > `entwurf_peers` will list both as citizens. That is a **known open gap**, not a
272
- > promise: closing it on the dispatch path is [#52](https://github.com/junghan0611/entwurf/issues/52).
264
+ > **identity writes**, in the doctor, and on the two read surfaces below — not on every
265
+ > mailbox poke; a call-relay does not re-scan the whole store per message. What every
266
+ > **targeted read** holds is the per-entry half of the same contract:
267
+ > `readMetaIdentityByGardenId` refuses a record that is not a regular file (a symlink is
268
+ > never followed, in *either* direction) and one whose body disagrees with its name,
269
+ > naming the verb. That is what the mailbox poke, the sender-marker trust and
270
+ > `entwurf_self` use, and it is all they need.
271
+ >
272
+ > Store-wide **uniqueness** is checked on the read snapshot at the two places where it
273
+ > is both affordable and load-bearing ([#52](https://github.com/junghan0611/entwurf/issues/52),
274
+ > 0.12.9):
275
+ >
276
+ > - **Discovery** — `listAllMetaIdentities`, and so `entwurf_peers`, already reads the
277
+ > whole store, so the check is free. Two records claiming one `nativeSessionId` are
278
+ > **not** two citizens: *neither* is listed (the store cannot say which one owns that
279
+ > session, and a facts surface may not mint an authority the certification refuses),
280
+ > both become diagnostics naming each other, and every unrelated citizen keeps listing.
281
+ > - **Dispatch** — `readAddressableMetaIdentity`, used by v2 `resolveTarget` and by the
282
+ > pi resume path. Those are the moments a record stops being data and becomes an
283
+ > **address**, they happen once per dispatch next to a socket connect and a spawn, and
284
+ > a duplicate there means direct-injecting one live conversation under two garden ids,
285
+ > or resuming one transcript twice under two per-garden-id locks. It fails **loud**; a
286
+ > soft `bad-target` is reserved for a record that is genuinely absent.
287
+ >
288
+ > **A rival is a record that could be addressed instead** — narrower than "a file whose
289
+ > bytes mention the same id". A **symlinked** entry is not a candidate and is *never
290
+ > read* (rule 1 again: following it to see whether it counts would break the rule in the
291
+ > act of enforcing it, and let planted foreign bytes quarantine a healthy citizen); a
292
+ > **drifted** or **unparseable** neighbour is not a candidate either, because no garden
293
+ > id can reach it. All three remain certification defects and the listing reports them as
294
+ > diagnostics — they just may not blind a healthy record. The opposite case is a
295
+ > **regular `.meta.json` this process cannot read**: that one might BE the duplicate, so
296
+ > it fails loud rather than being skipped, because "holds it alone" from a scan that
297
+ > never asked is the same vacuous pass in miniature. (`ENOENT` alone is the exception —
298
+ > a file that vanished mid-scan is not in the store.)
299
+ >
300
+ > Both store-wide read scans take entries **with their kind** from one shared
301
+ > `readActiveStoreEntries`, rather than each binding doing its own name-only `readdir`.
302
+ > That is what makes rule 1 structural: a scan handed bare names has no choice but to
303
+ > read the path, which is how both `entwurf_peers` bindings came to follow a symlinked
304
+ > record while the doctor refused the very same entry.
305
+ >
306
+ > A kind carried alongside a **name** is still only half of it, because a name can stop
307
+ > meaning what it meant. `lstat`-then-`readFileSync(path)` classifies one entry and reads
308
+ > another: replace the final path component with a symlink in between, and the read
309
+ > follows it into foreign bytes while every test on a settled store stays green. So the
310
+ > bytes of a record come from exactly one place — `readStoreRecordFile`, shared by the
311
+ > store-wide reader and by `readMetaIdentityByGardenId` — which opens with `O_NOFOLLOW`
312
+ > (a symlink fails the **open**, before a byte is read), decides the kind by `fstat` on
313
+ > **that file description** rather than on a name, and closes it in a `finally`. It also
314
+ > opens `O_NONBLOCK`, because classify-then-open never had to care that `open(fifo,
315
+ > O_RDONLY)` blocks until a writer appears, and deciding on the fd does. The reader does
316
+ > not flatten errno: callers still separate a record that raced away (`ENOENT`, skipped)
317
+ > from one that cannot be read (`EACCES`, loud) from one that was swapped (`ELOOP`,
318
+ > refused) — and the rival scan's raced-away skip depends on exactly that.
319
+ >
320
+ > That reader does not replace the `lstat` classification in front of the targeted read;
321
+ > the two hold **different** things, and collapsing them into "one enforcement point"
322
+ > was itself a regression (caught in review before shipping). The classification decides
323
+ > POLICY on a settled store **without opening anything**, which is what lets a socket, a
324
+ > device or a mode-000 directory earn the certification's own sentence — an `open` would
325
+ > answer `ENXIO` or `EACCES` there, errnos that say nothing about regularity, and the
326
+ > targeted read would start calling the host unreadable where the doctor calls the entry
327
+ > non-regular. Two contracts for one store is precisely the defect rule 1 exists to
328
+ > prevent. The fd layer decides the RACE: after a regular snapshot, its errno verdicts
329
+ > (`ELOOP`, `ENXIO`, a non-regular `fstat`) collapse back onto the settled sentences
330
+ > through one pure classifier, so a race never teaches the operator a second vocabulary
331
+ > for one state of the world. Because the classification answers first, those branches
332
+ > are unreachable from any settled store — which is why the classifier is pure and pinned
333
+ > with synthetic errnos rather than by a store on disk.
334
+ >
335
+ > This is not only a defence against external corruption. `upsertMetaSession` certifies
336
+ > and then writes, which is **not a transaction**, so two concurrent births — two
337
+ > `SessionStart` hooks, an `entwurf_register_native` racing an agy imprint — can both
338
+ > observe one clean store and mint different garden ids for one native session. A
339
+ > duplicate can therefore appear on a host where nothing was ever corrupted.
273
340
  >
274
341
  > There is **no migrator and no legacy reader anywhere in this repo** — carrying
275
342
  > old records forward would serve a continuity the system deliberately does not
@@ -290,6 +357,23 @@ Only that accepted file may be published under the explicitly authorized lane:
290
357
  > entwurf meta-bridge-fresh-cut # quiesce-checked: archive the old generation, open an empty one
291
358
  > ```
292
359
  >
360
+ > **Read its exit status, don't just chain it.** The cut answers with a contract
361
+ > ([#54](https://github.com/junghan0611/entwurf/issues/54), `--help` prints it), because
362
+ > "it failed" is not one world-state:
363
+ >
364
+ > | exit | what already moved | what to do |
365
+ > |---|---|---|
366
+ > | `0` | the cut is complete | run `setup` |
367
+ > | `1` | **nothing** — a live/unprovable surface, an occupied archive destination, an unreadable surface | fix the named cause, re-run. **Do not** run `setup`: the store it refused is still there |
368
+ > | `2` | nothing — usage error | fix the command |
369
+ > | `3` | the cut transition is **incomplete** after at least one archive move; the fresh generation is not confirmed open | inspect, or re-run to finish under a new stamp |
370
+ > | `4` | the cut is **complete**; marker/socket residue could not be unlinked | `setup` may run. Prefer repairing the named residue before `setup`; if new citizens have already been born, remove it manually — another fresh-cut would archive their generation too |
371
+ >
372
+ > Only `0` is success — a failed sweep never becomes a pass. `fresh-cut && setup` is
373
+ > still the right chain for the common path; the codes are there so a runbook, CI or an
374
+ > agent can tell a refusal that changed nothing from a cut that already unblocked the
375
+ > install. An exit-4 re-run is safe only before `setup` or any new citizen birth.
376
+ >
293
377
  > The refusal is a **preflight, not a lock**: it certifies the store as it stands
294
378
  > at that moment. On a host whose pi/Claude settings point straight at a checkout,
295
379
  > a `git pull` can put the new code in front of live sessions before you run
@@ -304,6 +388,34 @@ Only that accepted file may be published under the explicitly authorized lane:
304
388
  > refuses the cut before anything moves. Cutting needs proof of death, not absence
305
389
  > of proof of life.
306
390
  >
391
+ > **One marker is cleared without proving death, and it is the exception that keeps
392
+ > this path open.** A marker whose recorded `ownerPid` cannot own anything — `1`
393
+ > (init), `0`, a negative or non-integer — is *refuted by construction*: no writer in
394
+ > this tree can mint one any more, so on a current install it is **legacy or corrupt
395
+ > residue** — a pre-fix writer whose parent had been reparented to init (the retired
396
+ > shell-form Claude hook; the agy imprint, which asked only `> 0` until this repair),
397
+ > or a foreign/damaged marker, the only way a non-integer pid appears at all. The one
398
+ > file actually observed was a shell-form hook reparented to init. Honoring it was not
399
+ > merely wrong, it was a trap: init runs for the whole boot and its start-key does not
400
+ > change while it does, so the owner verdict is `live` and **the very action this
401
+ > refusal prescribes cannot change that** — you quiesce every session, exactly as
402
+ > told, and the cut refuses again. (Deleting the marker removes the claim rather than
403
+ > refuting the verdict; a reboot recomputes the key with no contract either way.)
404
+ > Meanwhile the one repair this page names could not run: on the affected host the cut
405
+ > stayed blocked until the marker file was removed by hand (#53 A, measured on a second
406
+ > Linux host 2026-07-25). Such a marker is now swept as residue and **reported apart
407
+ > from the dead ones** (`refuted:`), because a proof of invalidity is a different
408
+ > finding from a proof of death — and a stronger one.
409
+ >
410
+ > **Scope of that rule.** "A native session is never owned by init" is a property of the
411
+ > axis entwurf certifies — a Linux desktop/workstation host, where init is the service
412
+ > manager and every harness descends from a login session. A container that runs the
413
+ > harness **as pid 1** is a real shape, and there the marker would name a genuine owner.
414
+ > That host is **unsupported and fails closed**: the writers refuse the marker, so the
415
+ > session still gets its meta-record but never claims reply-addressability — a lost
416
+ > capability rather than a false identity. Reopening that lane needs new evidence and a
417
+ > new contract, not a looser predicate.
418
+ >
307
419
  > That agy row is not symmetry for its own sake: `entwurf_register_native` writes a
308
420
  > record and **no marker at all**, and `entwurf_v2` dispatches to such a citizen
309
421
  > straight off the record, so marker absence is the *normal* state of a live,
@@ -420,12 +532,12 @@ Reference shape lives in [`pi/settings.reference.json`](./pi/settings.reference.
420
532
 
421
533
  **Which verb an external agent should reach for:** to deliver to / reply to a garden id, use **`entwurf_v2`** — it is the canonical delivery surface and the only one that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, or native-push Antigravity and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation (normal agy birth is automatic through the installed hook). Fresh sibling creation from nothing is a deferred lane. (The old v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.)
422
534
 
423
- Observed: Claude Code, Codex CLI, and Antigravity CLI all reach the fact surfaces (`entwurf_peers`, inbox) through this MCP bridge from a plain external host; **sending** needs an identity lane. Claude becomes symmetric/replyable through its mailbox-backed meta-session; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
535
+ Observed: Claude Code, Codex CLI, and Antigravity CLI all reach the read surfaces through this MCP bridge from a plain external host — `entwurf_peers` is a pure fact projection, while `entwurf_inbox_read` is a **mutating drain** (it archives the messages and stamps the read-receipt), so "read" here does not mean side-effect-free; **sending** needs an identity lane. Claude becomes symmetric/replyable through its mailbox-backed meta-session; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
424
536
 
425
537
  Prerequisites on the host running the external MCP client:
426
538
 
427
539
  - `pi` on PATH (for the `owned-outcome` spawn-bg resume path).
428
- - A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<sessionId>.sock`; required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
540
+ - A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<gardenId>.sock` the key is the **record's** garden id, never a transcript/session id (`PI_SESSION_ID` only carries the id record birth already established). Required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
429
541
 
430
542
  > **PATH boundary.** MCP servers are often launched by GUI/editor daemons and may not inherit the interactive shell's PATH. If `pi` works in your terminal but an external-host `entwurf_v2` spawn-bg resume fails with `spawn pi ENOENT`, pass a full PATH in the MCP server `env`, set `ENTWURF_BRIDGE_ENV_FILE` to a small shell file that exports PATH, or point the host at a wrapper that can find `pi`. `start.sh` sources only the explicit `ENTWURF_BRIDGE_ENV_FILE`; it never reads personal dotfiles automatically.
431
543
 
@@ -454,7 +566,7 @@ Emergency/manual workaround when the MCP server environment is wrong but an exis
454
566
  External/meta-session semantics:
455
567
 
456
568
  - `entwurf_v2` from a plain external host is **refused by default** (no authoritative sender — #50 C4). With the explicit `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch it delivers with `origin: "external-mcp"` / `replyable: false`; there is still no reply address.
457
- - `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"` / `replyable: true`; `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
569
+ - `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"`, and `replyable` is **derived from that sender's own rail — not granted by being trusted**: a self-fetch sender (Claude Code) is replyable only while its receiver is live and armed, and a native-push sender (Antigravity) only while its adapter probe finds the live conversation. Identity survives either way; only `replyable` drops to `false`. When it is `true`, `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
458
570
  - `entwurf_v2` with `intent: "owned-outcome"` to a dormant pi target needs `pi` on PATH (it spawns a `pi --entwurf-control` resume child); async completion followUp requires a replyable pi control-socket caller.
459
571
  - `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env and no trusted sender marker still fails because there is no reply address to report.
460
572
 
@@ -519,7 +631,7 @@ entwurf doctor-agy-hooks
519
631
 
520
632
  The three adapters deliberately own different atoms:
521
633
 
522
- - bridge: one `entwurf-bridge` server in `~/.gemini/config/mcp_config.json`, plus exactly one permission string — `mcp(entwurf-bridge/entwurf_v2)` — in `~/.gemini/antigravity-cli/settings.json`;
634
+ - bridge: one `entwurf-bridge` server in `~/.gemini/config/mcp_config.json`, plus one narrow permission string per tool the normal agy workflow calls — `mcp(entwurf-bridge/entwurf_v2)`, `mcp(entwurf-bridge/entwurf_peers)`, `mcp(entwurf-bridge/entwurf_self)` — in `~/.gemini/antigravity-cli/settings.json`. agy defaults every `mcp` action to Ask, so a tool that ships without its own rule stops for a y/n on every call; `entwurf_inbox_read` is deliberately not granted (native-push has no inbox) and neither is the manual `entwurf_register_native` fallback;
523
635
  - statusline: the complete `statusLine` subtree pointing at the bare stable bin `entwurf-agy-statusline`;
524
636
  - hooks: one named `PreInvocation` hook pointing at the bare stable bin `entwurf-agy-imprint`.
525
637
 
@@ -543,17 +655,22 @@ The Claude ACP backend keeps its native model / API / tools; entwurf shapes only
543
655
 
544
656
  Antigravity is also not an ACP backend. It is a native-push citizen: `PreInvocation` supplies birth/sender identity, `entwurf_v2` probes and direct-injects replies into the live conversation, and no mailbox/receiver marker is involved.
545
657
 
546
- Pi is the canonical memory authority (semantic-memory + Denote llmlog); Claude's native memory layer is pinned off.
658
+ entwurf owns **no** memory layer at all — the ACP plugin's boundary explicitly excludes a memory DB (see `AGENTS.md` §ACP Plugin Boundary), and no backend is a memory authority for another. What this overlay does is narrower: Claude's native memory layer is pinned off so operator memory, project state, and history never leak into an ACP session. Whatever semantic-memory / Denote tooling an operator runs is their own skill surface on whichever harness hosts it — deliberately kept out of the MCP bridge, and not a pi privilege.
547
659
 
548
660
  ## Smoke commands
549
661
 
550
662
  ```bash
551
663
  pnpm check # full deterministic floor (all check-* gates, incl. check-acp-*)
552
664
  ./run.sh check-bridge # entwurf-bridge direct MCP smoke (no backend auth)
553
- ./run.sh smoke-agy-install-state # agy MCP + exact permission ownership (120 checks)
554
- ./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface (62 checks)
555
- ./run.sh smoke-agy-hooks-state # agy PreInvocation birth hook (37 checks)
556
- ./run.sh check-agy-sender-identity # record-backed pid/start-key sender identity (28 checks)
665
+ ./run.sh smoke-agy-install-state # agy MCP + exact permission ownership lifecycle (install/uninstall/doctor/inverse)
666
+ ./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface
667
+ ./run.sh smoke-agy-hooks-state # agy PreInvocation birth hook
668
+ ./run.sh check-agy-sender-identity # record-backed pid/start-key sender identity
669
+
670
+ # source-maintainer only — qualification snapshots the git work surface, and both
671
+ # commands are source-contract gates rather than installed operator checks:
672
+ ./run.sh check-agy-permission-matrix # AGY permission contract space as a literal table (declared cells + stated exclusions)
673
+ ./run.sh check-gate-qualification # kill-proof: committed defect mutants must turn their gates red for the claimed reason
557
674
 
558
675
  # agy LIVE acceptance — requires an already-running conversation:
559
676
  LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live
@@ -569,6 +686,14 @@ LIVE=1 ./run.sh smoke-acp-carrier-augment-live # augment delivery + empty-carri
569
686
  LIVE=1 ./run.sh release-gate /tmp/scratch # the single cut gate (MUST + BEHAVIOR, SKIP=0 for a real cut)
570
687
  ```
571
688
 
689
+ `pnpm check` already includes the two maintainer gates: the AGY permission contract
690
+ matrix and the full committed-mutant gate qualification run on every pass. A gate a
691
+ release touches must kill its known defect for the claimed `[QK:<claim>]` reason —
692
+ the descriptions above name what each smoke covers, and no check count is quality
693
+ evidence on its own. Gate qualification needs the git work surface, while the matrix
694
+ is the source permission-contract gate; both run from a clone, never as a post-install
695
+ operator step.
696
+
572
697
  ## Custom skills
573
698
 
574
699
  Claude sessions accept custom skills through `skillPlugins` — an array of absolute paths to directories matching the Claude Agent SDK plugin layout:
@@ -604,7 +729,7 @@ For a real consumer arranging many skills, see [agent-config](https://github.com
604
729
 
605
730
  **Entwurf is one dispatch capability with native-pi and MCP surfaces.** Native pi exposes it directly as extension tools; ACP-backed and external native-harness sessions reach it through `entwurf-bridge`. The purpose is not to invent a different sub-agent system, but to preserve the same sibling-based model across harnesses.
606
731
 
607
- A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent. Minting a brand-new sibling from nothing is a deferred v2 lane (`spawn-fresh`); today every transport targets an *existing* garden citizen. `entwurf_v2` routes from rail-specific liveness + intent: live pi fire-and-forget → control socket; dormant pi owned-outcome → spawn-bg resume; active self-fetch → meta-mailbox; probe-alive agy → native-push. Pi paths use the per-target lock; mailbox/native-push use their own deliverability evidence and remain lock-free.
732
+ A sibling has its own runtime boundary and its own provider/model identity — not a worker, delegate, or sub-agent. Minting a brand-new sibling from nothing is a deferred v2 lane (`spawn-fresh`); today every transport targets an *existing* garden citizen. `entwurf_v2` routes from rail-specific liveness + intent: live pi fire-and-forget → control socket; dormant pi owned-outcome → spawn-bg resume; active self-fetch → meta-mailbox; probe-alive agy → native-push. A **control-socket-domain** dispatch takes the per-target lock — both the live send and the dormant cell's spawn-bg resume; mailbox and native-push use their own deliverability evidence and remain lock-free.
608
733
 
609
734
  A two-pane recording covers the surface end-to-end — sibling resume, cross-process MCP dispatch across a different cwd, and a live peer greeting:
610
735
 
@@ -615,13 +740,13 @@ A two-pane recording covers the surface end-to-end — sibling resume, cross-pro
615
740
 
616
741
  </details>
617
742
 
618
- Live peer messaging carries a sender envelope `{ sessionId, agentId, cwd, timestamp }`; `entwurf_self` returns that authoritative envelope for the current pi session or trusted meta-session. Plain external MCP hosts are non-replyable; garden-native meta-sessions carry a trusted `meta-session` envelope and are replyable by garden id. `wants_reply` is an etiquette marker rendered as a `(wants reply)` badge — not a transport contract, no wait, no polling and is rejected only from non-replyable external senders.
743
+ 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.)
619
744
 
620
745
  In ACP-backed and external native-harness sessions, `entwurf-bridge` exposes five tools: `entwurf_v2`, `entwurf_peers`, `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` 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 / dormant-resume / Claude-Code-meta-mailbox / Antigravity-native-push. Fresh sibling creation from nothing is a deferred lane. (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` resumes an already-identified record-backed citizen, never a model tuple from a file.
621
746
 
622
747
  ### `entwurf_v2` — canonical dispatch verb
623
748
 
624
- `entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget` or `owned-outcome`); one decider reads the target's liveness as a fact and picks the transport from a frozen table keyed on **both** the target's state **and** the intent — never on state alone — then reports one outcome under the v2 lock policy. Pi control-socket and spawn-bg paths take a per-target lock; mailbox and native-push are lock-free, with deliverability guarded by their own receiver/probe evidence:
749
+ `entwurf_v2` / `runEntwurfV2` is the canonical v2 dispatch verb over **existing** garden targets — record-backed citizens only (#50 C4: the record is the sole address authority; a record-less control socket rejects pre-probe as `record-less-socket`, a diagnostic state, never a delivery target). You give a target garden id plus an intent (`fire-and-forget` or `owned-outcome`); one decider reads the target's liveness as a fact and picks the transport from a frozen table keyed on **both** the target's state **and** the intent — never on state alone — then reports one outcome under the v2 lock policy. A **control-socket-domain** dispatch takes a per-target lock — the live control-socket send and the dormant cell's spawn-bg resume alike, even though spawn-bg is a separate relaunch transport; mailbox and native-push are lock-free, with deliverability guarded by their own receiver/probe evidence:
625
750
 
626
751
  | target state | intent | transport |
627
752
  |---|---|---|
@@ -683,7 +808,7 @@ This repo also doubles as the maintainer's working laboratory for agent-harness
683
808
 
684
809
  ## Verification surfaces
685
810
 
686
- - **[VERIFY.md](./VERIFY.md)** — agent-driven. One ACP-bridged identity runs the script against another and records what it sees. Carries the Evidence Levels L0–L5 rung ladder and the Claims Ledger so each claim is parked at the rung it has actually reached.
811
+ - **[VERIFY.md](./VERIFY.md)** — agent-driven. One ACP-bridged identity runs the script against another and records what it sees. Carries the Evidence Levels L0–L5 rung ladder and the Claims Ledger so each claim is parked at the rung it has actually reached, and owns the deterministic-floor kill-proof protocol (gate qualification and its `[QK:<claim>]` coordinates).
687
812
  - **[BASELINE.md](./BASELINE.md)** — operator-driven. The maintainer runs the interview directly (no agent in the verifier seat) and the result is recorded.
688
813
  - **[DELIVERY.md](./DELIVERY.md)** — capability-coordinate. The cross-harness yardstick for one question: can an already-running native session receive an async message without pretending pi owns the backend transcript? Records the per-backend async-delivery level (`D0–D8`) each harness actually reaches instead of collapsing into works/doesn't.
689
814
 
package/VERIFY.md CHANGED
@@ -33,7 +33,8 @@ Verification here is not a benchmark. In production we exchange short turns and
33
33
 
34
34
  ### The canonical floor — two entry points
35
35
 
36
- - **Deterministic floor:** `pnpm check` — the full `check-*` gate set (~60 gates). Run first; it is the cheap, machine-checkable layer.
36
+ - **Deterministic floor:** `pnpm check` — the full `check-*` gate set (the `check` script in `package.json` is the SSOT for what runs). Run first; it is the offline, machine-checkable layer.
37
+ - **Discriminating power of that floor:** `./run.sh check-gate-qualification` (inside `pnpm check`) 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).
37
38
  - **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir>` — `pnpm check` + the v2-native live gates + the ACP plugin acceptance floor. It reports a **two-tier summary**:
38
39
  - **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm check`, `smoke-entwurf-v2-spawn-resume-live`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), and 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). (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
39
40
  - **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`).
@@ -109,7 +110,7 @@ GLG decisions.
109
110
 
110
111
  ### Verifying the two capabilities a gate cannot fully judge
111
112
 
112
- - **Garden-id delivery:** discover a target with `entwurf_peers`, then `entwurf_v2` with the correct intent — `fire-and-forget` for live pi, mailbox-backed meta, or native-push targets; `owned-outcome` only to wake a dormant record-backed pi citizen. Picking the wrong intent is rejected, never auto-fixed.
113
+ - **Garden-id delivery:** discover a target with `entwurf_peers`, then `entwurf_v2` with the correct intent — `fire-and-forget` for live pi, mailbox-backed meta, or native-push targets; `owned-outcome` only on a dormant target in the control-socket liveness domain (currently backend `pi`), where it selects **spawn-bg — a relaunch transport, not the control-socket rail that carries live sends**; the launch leaf checks backend authority. Picking the wrong intent is rejected, never auto-fixed.
113
114
  - **ACP continuity:** a direct `pi --provider entwurf --model claude-sonnet-5` turn, or the `smoke-acp-session-reuse-live` gate (process-scoped reuse + recall). Multi-turn reuse is proven by that gate, not by any v1 resume tool.
114
115
  - **agy citizenship:** in a fresh agy conversation, the first `PreInvocation` must yield a garden id, `entwurf_self` must report `agentId=meta-session/antigravity` and `replyable:true` only while the native probe is alive, and a reply to that same garden id must direct-inject into the same conversation. No mailbox/receiver-marker evidence counts on this rail.
115
116
 
package/demo/README.md CHANGED
@@ -113,7 +113,7 @@ The demo launch lines correspond to your shell aliases:
113
113
 
114
114
  | Alias | Model id | Use as |
115
115
  |---|---|---|
116
- | `piao` | `entwurf/claude-opus-4-8` | `SENDER_MODEL` (precision scenes) |
116
+ | `piao` | `entwurf/claude-opus-5` | `SENDER_MODEL` (precision scenes) |
117
117
  | `pias` | `entwurf/claude-sonnet-5` | `SENDER_MODEL` (default) |
118
118
  | `piat` | `entwurf/gpt-5.4` | `PEER_MODEL` (default) |
119
119
  | `piat5` | `entwurf/gpt-5.5` | either |
@@ -137,7 +137,7 @@ SCENE_DELAY=30 FINAL_PAUSE=10 bash demo.sh
137
137
 
138
138
  ## Prerequisites
139
139
 
140
- - `pi` on PATH (current floor 0.82.0)
140
+ - `pi` on PATH (current floor 0.82.1)
141
141
  - `entwurf` provider configured + auth ready for the selected sender/peer models
142
142
  - `asciinema` installed
143
143
  - `agg` installed (optional — only for GIF conversion)
package/demo/demo.sh CHANGED
@@ -1,5 +1,11 @@
1
1
  #!/usr/bin/env bash
2
- # entwurf-demo.sh — one-shot recorded demo of entwurf entwurf flow.
2
+ # entwurf-demo.sh — one-shot recorded demo of the entwurf flow.
3
+ #
4
+ # ARCHIVED pre-0.12 evidence — NOT a runnable recipe. The scenes below drive the
5
+ # retired v1 verbs (`entwurf` / `entwurf_resume` / `entwurf_send`), which the 0.12
6
+ # cutover removed; a run would fail at scene 1. Kept for historical comparison only.
7
+ # See demo/README.md. Scene 3's delivery proof was recovered as a deterministic gate
8
+ # (scripts/check-bridge-delivery.ts); the v2-native retake is a post-0.12 follow-up.
3
9
  #
4
10
  # Layout (tmux, 220x50):
5
11
  # pane 0 (top) — peer pi (codex, gpt-5.4) — idle, waits for greeting
@@ -65,7 +65,7 @@ exit 0.
65
65
  | Claude Code | **`>=2.1.217`** — the exec-form hook floor; an older Claude drops the hook's `args` silently and still reports success, so there is no fallback lane | `entwurf.claudeCodeFloor` (bound by `check-claude-floor-coherence`) |
66
66
  | npm | bundled with Node 24 | public package install path |
67
67
  | entwurf | `@junghanacs/entwurf` | neutral npm package; exposes `entwurf`, `entwurf-bridge`, `entwurf-statusline`, `entwurf-agy-statusline`, and `entwurf-agy-imprint` bins |
68
- | pi binary | **optional**, `@earendil-works/pi-coding-agent >=0.82.0 <0.83` | needed only for the pi adapter / ACP provider / spawn-bg resume lane |
68
+ | pi binary | **optional**, `@earendil-works/pi-coding-agent >=0.82.1 <0.83` | needed only for the pi adapter / ACP provider / spawn-bg resume lane |
69
69
  | Antigravity `agy` | **optional**, operator-installed/authenticated native CLI | needed only for the shipped native-push citizen lane; entwurf never moves its auth |
70
70
 
71
71
  ## Stage 0 — Node 24 via nvm
@@ -155,7 +155,7 @@ If the host will run pi sessions or the Claude ACP provider through pi, install
155
155
  a compatible pi binary separately and wire the target project.
156
156
 
157
157
  ```bash
158
- npm install -g @earendil-works/pi-coding-agent@0.82.0
158
+ npm install -g @earendil-works/pi-coding-agent@0.82.1
159
159
  pi --version
160
160
 
161
161
  mkdir -p ~/entwurf-smoke
@@ -172,7 +172,7 @@ Drift points:
172
172
  `entwurf-bridge`. (The `entwurf-targets.json` link is gone — #50 C3 removed the
173
173
  target registry; a leftover operator link is inert.)
174
174
  - Older pi versions may silently miss the provider/extension surface. Use the
175
- pinned floor (`>=0.82.0 <0.83`) for release verification.
175
+ pinned floor (`>=0.82.1 <0.83`) for release verification.
176
176
  - A host that only uses the external MCP bridge can skip this stage until it
177
177
  needs `owned-outcome` spawn-bg resume or pi-native control sockets.
178
178
 
@@ -235,6 +235,17 @@ host has nothing to cut and can ignore this paragraph. The refusal is a
235
235
  preflight, not a lock: for checkout-backed installs, quiesce sessions before
236
236
  pull, then fresh-cut, setup, and reopen.
237
237
 
238
+ Read the cut's exit status rather than only chaining it (#54; `--help` prints the
239
+ contract): `0` complete → run `setup`; `1` NOTHING MOVED — a live/unprovable
240
+ surface, an occupied archive destination, an unreadable surface — fix the named
241
+ cause and re-run, and do not run `setup`, because the store it refused is still
242
+ there; `2` usage; `3` CUT TRANSITION INCOMPLETE — at least one archive move
243
+ happened but the fresh generation is not confirmed open — inspect, or re-run to
244
+ finish under a new stamp; `4` the cut is COMPLETE but marker/socket residue could
245
+ not be unlinked — `setup` may run. Prefer fixing the named residue and re-running
246
+ before `setup`; if new citizens have already been born, remove it manually rather
247
+ than fresh-cutting their new generation. Only `0` is success.
248
+
238
249
  Upgrade invariant: every global npm/pnpm package upgrade must be followed by
239
250
  `entwurf install-meta-bridge` from that same installed binary and then
240
251
  `entwurf doctor-meta-bridge`. Installed statusline/MCP entries use stable bin
@@ -252,9 +263,13 @@ A plain external MCP host can call the read surfaces (`entwurf_peers`,
252
263
  A deliberately-anonymous host may wire the explicit
253
264
  `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch and then delivers external and
254
265
  non-replyable; see README §"Wiring `entwurf-bridge` into an external MCP host".
255
- A garden-native meta-session has a garden id, a mailbox, and a trusted sender
256
- marker; it can call `entwurf_self`, receive mailbox wakeups, and be replied to by
257
- garden id.
266
+ A garden-native meta-session has a garden id and a trusted sender marker, so it can
267
+ call `entwurf_self` and be addressed by garden id. **Whether it has a mailbox depends
268
+ on its rail**: a self-fetch backend (Claude Code) has a drainable inbox and receives
269
+ mailbox wakeups, while a native-push backend (Antigravity) has **no mailbox and no
270
+ idle-wake watch at all** — a reply is injected straight into its live conversation, and
271
+ it is reachable only while the adapter probe finds that conversation. Do not assume a
272
+ mailbox from "garden-native meta-session".
258
273
 
259
274
  ## Stage 5 — Antigravity native citizen (optional)
260
275
 
@@ -276,7 +291,9 @@ entwurf doctor-agy-hooks
276
291
  What these commands own:
277
292
 
278
293
  - `install-agy-bridge`: one MCP server in `~/.gemini/config/mcp_config.json`
279
- and exactly `mcp(entwurf-bridge/entwurf_v2)` in
294
+ and one narrow rule per tool the normal agy workflow calls —
295
+ `mcp(entwurf-bridge/entwurf_v2)`, `mcp(entwurf-bridge/entwurf_peers)`,
296
+ `mcp(entwurf-bridge/entwurf_self)` — in
280
297
  `~/.gemini/antigravity-cli/settings.json`'s permission allow-list;
281
298
  - `install-agy-statusline`: the `statusLine` subtree only, pointing at
282
299
  `entwurf-agy-statusline`;