@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.
- package/AGENTS.md +134 -248
- package/BASELINE.md +1 -1
- package/CHANGELOG.md +39 -1
- package/DELIVERY.md +5 -4
- package/README.md +148 -23
- package/VERIFY.md +3 -2
- package/demo/README.md +2 -2
- package/demo/demo.sh +7 -1
- package/docs/setup-clean-host.md +24 -7
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +168 -81
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +12 -12
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +5 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +26 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +10 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +16 -18
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +13 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +31 -41
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +8 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +32 -25
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +5 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +14 -13
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +11 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +15 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +500 -54
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +8 -3
- package/mcp/entwurf-bridge/dist/scripts/agy-imprint.js +14 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +155 -29
- package/mcp/entwurf-bridge/src/index.ts +200 -94
- package/package.json +11 -9
- package/pi-extensions/entwurf-control.ts +81 -39
- package/pi-extensions/lib/acp/models.ts +12 -12
- package/pi-extensions/lib/acp/overlay.ts +5 -3
- package/pi-extensions/lib/entwurf-core.ts +26 -9
- package/pi-extensions/lib/entwurf-deliverability.ts +10 -6
- package/pi-extensions/lib/entwurf-fact-provider.ts +24 -19
- package/pi-extensions/lib/entwurf-facts.ts +13 -13
- package/pi-extensions/lib/entwurf-resume-args.ts +40 -46
- package/pi-extensions/lib/entwurf-self-address.ts +8 -9
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +7 -2
- package/pi-extensions/lib/entwurf-v2-contract.ts +32 -25
- package/pi-extensions/lib/entwurf-v2-decider.ts +8 -8
- package/pi-extensions/lib/entwurf-v2-lock.ts +5 -4
- package/pi-extensions/lib/entwurf-v2-production.ts +22 -13
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +11 -3
- package/pi-extensions/lib/meta-sender-identity.ts +15 -5
- package/pi-extensions/lib/meta-session.ts +543 -58
- package/pi-extensions/meta-bridge-hook.ts +8 -2
- package/run.sh +78 -67
- package/scripts/agy-bridge-config.py +249 -49
- package/scripts/agy-bridge.sh +59 -14
- package/scripts/agy-imprint.ts +15 -1
- package/scripts/check-acp-carrier-augment.ts +34 -2
- package/scripts/check-acp-sdk-surface.ts +22 -11
- package/scripts/check-acp-session-reuse.ts +1 -1
- package/scripts/check-acp-session-store.ts +3 -3
- package/scripts/check-agy-permission-matrix.py +655 -0
- package/scripts/check-agy-sender-identity.ts +83 -0
- package/scripts/check-entwurf-control-rpc.ts +2 -2
- package/scripts/check-entwurf-deliverability.ts +9 -6
- package/scripts/check-entwurf-fact-provider.ts +16 -8
- package/scripts/check-entwurf-facts.ts +13 -13
- package/scripts/check-entwurf-resume-args.ts +25 -63
- package/scripts/check-entwurf-self-address.ts +187 -4
- package/scripts/check-entwurf-session-identity.ts +7 -6
- package/scripts/check-entwurf-v2-contract.ts +2 -2
- package/scripts/check-entwurf-v2-production.ts +9 -7
- package/scripts/check-entwurf-v2-spawn-production.ts +8 -4
- package/scripts/check-entwurf-v2-surface.ts +327 -14
- package/scripts/check-fresh-cut-gate.sh +305 -4
- package/scripts/check-gate-qualification.ts +785 -0
- package/scripts/check-meta-identity-consumers.ts +501 -1
- package/scripts/check-meta-listing.ts +91 -9
- package/scripts/check-meta-receiver-marker.ts +54 -0
- package/scripts/check-model-lock.ts +1 -1
- package/scripts/check-shell-quote.ts +2 -1
- package/scripts/lib/mutation-qualify.ts +794 -0
- package/scripts/meta-bridge-fresh-cut.ts +164 -28
- package/scripts/mutants/acp-augment.json +30 -0
- package/scripts/mutants/agy-permission.json +144 -0
- package/scripts/mutants/meta-identity.json +17 -0
- package/scripts/mutants/self-address.json +59 -0
- package/scripts/mutants/v2-surface.json +87 -0
- package/scripts/pi_settings_io.py +65 -0
- package/scripts/register-pi-package.py +183 -37
- package/scripts/register-pi-provider.py +68 -10
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
- package/scripts/smoke-acp-v2-send-live.ts +33 -18
- package/scripts/smoke-agy-install-state.sh +205 -20
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -2
- package/scripts/smoke-meta-install-state.sh +1 -1
- package/scripts/smoke-pi-attach.ts +7 -2
- package/scripts/smoke-user-scope-citizen.sh +177 -0
- package/pi-extensions/lib/entwurf-mailbox-guard.ts +0 -100
- 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
|
-
-
|
|
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-
|
|
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`
|
|
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
|
|
220
|
-
`
|
|
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.
|
|
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
|
|
265
|
-
> not re-scan the whole store per message. What every
|
|
266
|
-
> the per-entry half of the same contract:
|
|
267
|
-
> record that is not a regular file (a symlink is
|
|
268
|
-
> direction) and one whose body disagrees with its name,
|
|
269
|
-
>
|
|
270
|
-
>
|
|
271
|
-
>
|
|
272
|
-
>
|
|
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
|
|
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/<
|
|
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"`
|
|
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
|
|
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
|
-
|
|
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 (
|
|
554
|
-
./run.sh smoke-agy-statusline-state # agy ambient garden-id install surface
|
|
555
|
-
./run.sh smoke-agy-hooks-state # agy PreInvocation birth hook
|
|
556
|
-
./run.sh check-agy-sender-identity # record-backed pid/start-key sender identity
|
|
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.
|
|
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
|
|
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.
|
|
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 (
|
|
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
|
|
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-
|
|
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.
|
|
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
|
|
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
|
package/docs/setup-clean-host.md
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
|
256
|
-
|
|
257
|
-
|
|
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
|
|
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`;
|