@junghanacs/entwurf 0.12.8-repair.0 → 0.12.8

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 (135) hide show
  1. package/AGENTS.md +48 -20
  2. package/BASELINE.md +94 -6
  3. package/CHANGELOG.md +46 -3
  4. package/DELIVERY.md +2 -2
  5. package/README.md +115 -50
  6. package/VERIFY.md +44 -37
  7. package/demo/README.md +1 -1
  8. package/docs/setup-clean-host.md +63 -25
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +50 -40
  10. package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +9 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-socket-path.js +70 -0
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +22 -0
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +62 -1189
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +37 -6
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +9 -17
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +69 -63
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +2 -2
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +6 -3
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +19 -33
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-mailbox.js +3 -2
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +45 -19
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +9 -10
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +50 -22
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +9 -0
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +43 -11
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +465 -491
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/native-push/adapter.js +40 -5
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +26 -56
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-probe.js +16 -19
  30. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +2 -3
  31. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-fresh-cut.js +547 -0
  32. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-prune.js +5 -4
  33. package/mcp/entwurf-bridge/dist/scripts/meta-bridge-store-doctor.js +52 -45
  34. package/mcp/entwurf-bridge/src/index.ts +50 -40
  35. package/mcp/entwurf-bridge/test.sh +1 -1
  36. package/mcp/entwurf-bridge/tsconfig.build.json +22 -2
  37. package/package.json +13 -15
  38. package/pi-extensions/entwurf-control.ts +201 -426
  39. package/pi-extensions/lib/control-socket-path.js +74 -0
  40. package/pi-extensions/lib/entwurf-control-rpc.ts +23 -0
  41. package/pi-extensions/lib/entwurf-core.ts +79 -1457
  42. package/pi-extensions/lib/entwurf-fact-provider.ts +55 -12
  43. package/pi-extensions/lib/entwurf-facts.ts +34 -58
  44. package/pi-extensions/lib/entwurf-mailbox-guard.ts +2 -2
  45. package/pi-extensions/lib/entwurf-peers-render.ts +74 -80
  46. package/pi-extensions/lib/entwurf-resume-args.ts +11 -5
  47. package/pi-extensions/lib/entwurf-v2-contract.ts +6 -3
  48. package/pi-extensions/lib/entwurf-v2-decider.ts +38 -53
  49. package/pi-extensions/lib/entwurf-v2-mailbox.ts +3 -2
  50. package/pi-extensions/lib/entwurf-v2-production.ts +40 -14
  51. package/pi-extensions/lib/entwurf-v2-send-fallback.ts +9 -10
  52. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +67 -39
  53. package/pi-extensions/lib/entwurf-v2-surface.ts +11 -0
  54. package/pi-extensions/lib/meta-sender-identity.ts +44 -9
  55. package/pi-extensions/lib/meta-session.ts +541 -604
  56. package/pi-extensions/lib/native-push/adapter.ts +42 -4
  57. package/pi-extensions/lib/native-push/register.ts +2 -2
  58. package/pi-extensions/lib/pi-citizen-birth.ts +93 -0
  59. package/pi-extensions/lib/socket-discovery.ts +31 -65
  60. package/pi-extensions/lib/socket-probe.ts +16 -20
  61. package/pi-extensions/meta-bridge-hook.ts +2 -3
  62. package/run.sh +610 -294
  63. package/scripts/build-bridge.sh +18 -0
  64. package/scripts/check-acp-prompt-builder.ts +5 -3
  65. package/scripts/check-acp-sdk-surface.ts +38 -24
  66. package/scripts/check-agy-sender-identity.ts +66 -1
  67. package/scripts/check-bridge-delivery.ts +589 -0
  68. package/scripts/check-capability-bundle-reach.ts +130 -0
  69. package/scripts/check-control-socket-path.ts +124 -0
  70. package/scripts/check-entwurf-capabilities.ts +19 -17
  71. package/scripts/check-entwurf-control-rpc.ts +38 -3
  72. package/scripts/check-entwurf-fact-provider.ts +50 -19
  73. package/scripts/check-entwurf-facts.ts +56 -44
  74. package/scripts/check-entwurf-mailbox-guard.ts +1 -3
  75. package/scripts/check-entwurf-peers-surface.ts +130 -91
  76. package/scripts/check-entwurf-resume-args.ts +17 -8
  77. package/scripts/check-entwurf-self-address.ts +13 -5
  78. package/scripts/check-entwurf-session-identity.ts +61 -545
  79. package/scripts/check-entwurf-v2-contract.ts +17 -25
  80. package/scripts/check-entwurf-v2-decider.ts +32 -109
  81. package/scripts/check-entwurf-v2-matrix.ts +3 -5
  82. package/scripts/check-entwurf-v2-production.ts +80 -33
  83. package/scripts/check-entwurf-v2-release.ts +1 -0
  84. package/scripts/check-entwurf-v2-runner.ts +1 -0
  85. package/scripts/check-entwurf-v2-send-fallback.ts +18 -38
  86. package/scripts/check-entwurf-v2-send.ts +1 -0
  87. package/scripts/check-entwurf-v2-spawn-production.ts +119 -24
  88. package/scripts/check-entwurf-v2-spawn.ts +1 -0
  89. package/scripts/check-entwurf-v2-surface.ts +11 -0
  90. package/scripts/check-fresh-cut-gate.sh +1193 -0
  91. package/scripts/check-install-container.sh +245 -3
  92. package/scripts/check-install-surface.ts +13 -8
  93. package/scripts/check-mailbox-receipt-state.ts +6 -3
  94. package/scripts/check-meta-capability-source.ts +16 -54
  95. package/scripts/check-meta-doctor-oracle.sh +126 -7
  96. package/scripts/check-meta-identity-consumers.ts +470 -0
  97. package/scripts/check-meta-listing.ts +3 -5
  98. package/scripts/check-meta-mailbox-state-write.ts +4 -4
  99. package/scripts/check-meta-manifest-schema.py +8 -5
  100. package/scripts/check-meta-receiver-marker.ts +90 -0
  101. package/scripts/check-meta-session.ts +19 -251
  102. package/scripts/check-meta-v3-record.ts +194 -0
  103. package/scripts/check-native-push-adapter.ts +47 -2
  104. package/scripts/check-socket-discovery.ts +13 -40
  105. package/scripts/check-socket-probe.ts +4 -28
  106. package/scripts/lib/pi-record-discovery.ts +44 -0
  107. package/scripts/meta-bridge-doctor.sh +284 -22
  108. package/scripts/meta-bridge-fresh-cut.ts +603 -0
  109. package/scripts/meta-bridge-install.sh +74 -13
  110. package/scripts/meta-bridge-prune.ts +5 -4
  111. package/scripts/meta-bridge-state.py +5 -6
  112. package/scripts/meta-bridge-store-doctor.ts +60 -50
  113. package/scripts/resident-rpc-drive.ts +285 -0
  114. package/scripts/smoke-acp-bundled-mcp-live.ts +66 -33
  115. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  116. package/scripts/smoke-acp-socket-citizen-live.ts +31 -26
  117. package/scripts/smoke-acp-v2-send-live.ts +345 -0
  118. package/scripts/smoke-agy-statusline-state.sh +13 -8
  119. package/scripts/smoke-entwurf-v2-matrix-live.ts +83 -95
  120. package/scripts/smoke-entwurf-v2-spawn-live.ts +15 -2
  121. package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +85 -44
  122. package/scripts/smoke-meta-install-state.sh +7 -13
  123. package/scripts/smoke-meta-prune.sh +12 -12
  124. package/scripts/smoke-pi-attach.ts +393 -0
  125. package/scripts/smoke-pi-provider-state.sh +12 -8
  126. package/scripts/smoke-resident-garden-guard.sh +216 -310
  127. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-resume-marker.js +0 -33
  128. package/pi/entwurf-targets.json +0 -17
  129. package/pi-extensions/lib/entwurf-v2-resume-marker.ts +0 -34
  130. package/scripts/check-meta-dual-consumers.ts +0 -154
  131. package/scripts/check-meta-dual-read.ts +0 -158
  132. package/scripts/check-meta-migration.ts +0 -212
  133. package/scripts/check-meta-record-v2.ts +0 -191
  134. package/scripts/gnew-rpc-drive.ts +0 -211
  135. package/scripts/smoke-session-id-name.ts +0 -187
package/AGENTS.md CHANGED
@@ -83,7 +83,7 @@ Warnings make agents blame themselves and flail. Broken tool state must surface
83
83
  2. **Dispatch is a function of liveness, not session type.** `entwurf_v2` never asks "is this a resume or a send" up front — it probes the target on its own rail and routes: live pi→control-socket, dormant pi→spawn-bg resume, active self-fetch→meta-mailbox, live native conversation→native-push. State is computed, never stored (a stored liveness bit is a lie).
84
84
  3. **A reject is honest, never cosmetic.** When a target cannot receive (dead, drifted identity, wrong state×intent), the decider returns a reject — no `✓ delivered`, no `.msg` written, no signal poke. Silent degraded "delivery" is forbidden.
85
85
  4. **MCP injection**: only via explicit `mcpServers` wiring. No ambient `~/.mcp.json` scanning, no automatic retrieval.
86
- 5. **Meta-record authority is the record body, never the filename.** `scanByNativeId` scans `.meta.json` bodies, throws on duplicate `nativeSessionId` (authority ambiguity is fail-fast), and never derives identity from a filename. A meta-record is nullable-at-birth (`model`/`transcriptPath` null until known); a backend↔wakeMode contradiction is corrupt-and-crash.
86
+ 5. **Meta-record authority is the record body, never the filename — and the ACTIVE store is certified as a whole, by one contract.** Identity comes from the `.meta.json` body; no filename is ever parsed for authority. `certifyActiveStore` is the single contract the install doctor and all four identity writers (pi birth, Claude hook, agy imprint, `entwurf_register_native`) share: every `.meta.json` entry is a **regular file** (a symlink is refused, never followed — its bytes live where this store has no ownership), **readable by the live schema**, **named by its own body**, and the **unique holder of its `nativeSessionId`**. Body-is-authority and name-must-agree are not in tension: the body decides *what a record says*, while a record parked under the wrong name is unreachable by garden id and so corrupts the *active store*. Any defect fails the whole write BEFORE it happens, naming the fresh-cut verb — including a defect involving neither of the writer's own ids, because a narrow "is there a record for MY native id" scan is how a store ends up certified by the doctor and written to by the runtime under two different contracts (the weaker one always wins at runtime). **The contract binds both directions, at the granularity each surface can afford:** the store-WIDE scan runs on identity writes and in the doctor, while every TARGETED read (`readMetaIdentityByGardenId`, and so v2 dispatch / `entwurf_self` / sender-marker trust) holds the per-entry half — a non-regular-file record is refused and never followed, and body/filename drift fails loud, both naming the verb. Certifying only on write while the read followed a symlink made the rule true exactly where nobody was addressed. Store-wide *uniqueness* is still not proven per read, so a store that would fail certification can still surface a duplicate `nativeSessionId` to `entwurf_peers` and to dispatch — a known open gap, tracked separately, never described as guarded. A meta-record is nullable-at-birth (`model`/`transcriptPath` null until known). Production reads schemaVersion-3 records only, and the repo carries NO legacy reader or migrator: a record the live schema cannot read fails loud naming the fresh-cut verb (`entwurf meta-bridge-fresh-cut` — archive the whole generation, open an empty one). The active store provides no cross-generation address or resume continuity; sessions flow, and memory lives in the native transcripts and the embedding axes, never in the bridge.
87
87
  6. **GC reclaims process resources only — never data.** meta-records and transcripts (the denote-id memory layer) are preserved; dormant/stale entries are archived/TTL'd, not deleted.
88
88
  7. **This is not a second harness**: no prompt reconstruction, no transcript hydration, no tool result ledger, no harness emulation. Native bridges front only a garden id plus their narrow delivery rail (Claude mailbox or agy native-push); they do not scrape transcripts or run a replacement control daemon.
89
89
  8. **Auth boundary is deployment-surface-agnostic**. This repo does not provide, copy, proxy, decrypt, or mediate any backend's credentials. Native-harness sessions read whatever auth state is visible in their own process filesystem; nothing here moves that.
@@ -127,7 +127,7 @@ pnpm typecheck # 3-config tsc fence (root + mcp + s
127
127
  pnpm check # full static floor: lint + typecheck + every check-*/smoke-* below
128
128
  ./run.sh check-entwurf-v2-matrix # the decider's state×intent table, read as an SSOT (REAL decideDispatch)
129
129
  ./run.sh check-entwurf-v2-decider # + -contract / -lock / -release / -send / -send-fallback / -mailbox / -runner / -production / -surface / -spawn / -spawn-production
130
- ./run.sh check-meta-session # + -record-v2 / -dual-read / -migration / -mailbox-state-write / -receiver-marker / -capability-source / -dual-consumers / -listing
130
+ ./run.sh check-meta-session # + -v3-record / -mailbox-state-write / -receiver-marker / -capability-source / -identity-consumers / -listing (one live schema; no legacy readers — see check-fresh-cut-gate for the generation boundary)
131
131
  ./run.sh check-meta-doctor-oracle # detection power of the release oracle: healthy fixture reaches `doctor: PASS`, 21 planted defects each turn it FAIL naming their own cause
132
132
  ./run.sh check-native-push-adapter # agy probe/route leaf; separate from pi socket and mailbox liveness
133
133
  ./run.sh check-agy-sender-identity # record-backed pid/start-key sender resolution + ambiguity refusal
@@ -164,26 +164,49 @@ If a gate fails or a claim drops below its needed evidence level, do not commit.
164
164
 
165
165
  Uses `entwurf` instead of `delegate` to avoid ecosystem collisions. spawn-bg resume creates a sibling, not a worker.
166
166
 
167
- - **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`, `entwurf_register_native` (explicit/manual fallback for an already-running native conversation). pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools + `/entwurf-sessions`, `/gnew` (`/garden-new`) commands. The v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and the `/entwurf` / `/entwurf-send` / `/entwurf-status` commands are **removed**.
167
+ - **Surface** — MCP `entwurf-bridge`: `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read`, `entwurf_register_native` (explicit/manual fallback for an already-running native conversation). pi-native (`pi-extensions/entwurf-control.ts`): `entwurf_v2`, `entwurf_peers` tools (#50 C4 removed the socket-scan `/entwurf-sessions` command). The v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and the `/entwurf` / `/entwurf-send` / `/entwurf-status` commands are **removed**.
168
168
  - **`entwurf_v2` is the one delivery verb.** Given a garden id, it classifies the target (live pi vs. dormant pi vs. mailbox meta-session vs. native-push citizen — a bare garden id does not reveal this) and routes correctly. It does **not** mint a fresh sibling: spawn-bg resumes an *already-identified* citizen, while native-register binds an *already-running* conversation. Fresh creation was the v1 `entwurf` verb and remains deferred.
169
169
  - **`entwurf_peers`** is a read-only fact surface (liveness / capability / identity / cwd-history). Do not bake verb-routing (`resumable`/`sendable`) into the fact layer; routing is the decider's job.
170
- - **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required.
171
- - Target registry: `pi/entwurf-targets.json` (spawn-bg resume allowlist). Identity Preservation Rule: no model override on resume.
170
+ - **`entwurf_self`** returns the authoritative identity envelope (pi-session env, or a trusted meta-session sender marker) and is identity-required. Its socketPath/mailboxPath lines are the CALLER's own transport diagnostics, not an identity surface — that is why they survive #50 C4 while `entwurf_peers` forbids every socket-shaped key/path (the peers listing points at OTHER citizens, where a socket path is an address claim).
171
+ - The target registry (`pi/entwurf-targets.json` + `setup:links`) is **gone** (#50 C3): v2 never spawns from a model tuple — `entwurf_v2` resumes an already-identified record-backed citizen, and dormant-resume authorization is record existence + the transcript-header ↔ `record.nativeSessionId` integrity check (the old `requireEntwurf` name-tag and resume-marker env are deleted). Bridge-extension routing survives as `getRegistryRouting` (caller-supplied tuple, ← resolve-acp-bridge). Identity Preservation Rule: no model override on resume.
172
172
  - `PI_SHELL_ACP_V2_ONLY=1` was the v1-refusal flag; with v1 removed on this branch its guard (`entwurf-v2-only.ts`) is gone too. `runEntwurfV2` was always flag-clean.
173
173
 
174
174
  > **Source-agnostic does not mean harness-agnostic.** 어디서 던지든 — GLG / sibling / external MCP host — entwurf 의 *target* 은 garden citizen 이다. spawn-bg resume 의 spawn surface 는 pi 자식 프로세스만 띄운다 (`pi --entwurf-control` keep-alive resident). 외부 MCP host 가 닿을 때도 target 은 이미 식별된 citizen 이어야 한다. *Model* 은 free axis (어느 형제 학교 모델이든), *spawn target* 은 harness 정합 axis.
175
175
 
176
176
  > **Naming pair.** *Entwurf* (기투, projection-of-self) — a resident agent throws siblings forward (resume / messaging). The resident-side counterpart is *Mitsein* (공존, being-with), defined in the resident's own knowledge base (cwd-scoped, not a global persona). This repo owns the entwurf substrate; resident-side conventions live where the resident wakes.
177
177
 
178
- ### Garden launcher — the resident session is garden-native or it blows up (0.9.0)
179
-
180
- Garden identity covers the operator's OWN `--entwurf-control` session, not just spawned children. A `--entwurf-control` session's header `id` MUST be a garden sessionId (`YYYYMMDDTHHMMSS-[0-9a-f]{6}`); pi assigns a `uuidv7` when `--session-id` is absent, so the launcher injects it and `entwurf-control` only enforces.
181
-
182
- - **Launch:** `pi --session-id "$(run.sh new-session-id)" --entwurf-control …` (operator alias). The id is fixed at launch — an extension cannot change it after pi's `newSession`. `run.sh new-session-id` is the `generateSessionId` SSOT; never reimplement the format in the shell.
183
- - **In-process new:** builtin `/new` stays blocked under `--entwurf-control` because it mints a uuid before extensions can inject an id. Use `/gnew` (alias `/garden-new`) for a same-terminal fresh garden session; it pre-creates a valid garden JSONL header and `switchSession()`es into it, so no uuid moment exists. A `/gnew` session quit before the first turn may appear in resume lists with message count 0; that is intentional, not an orphan. (`/gnew` births a fresh *operator* session in the same terminal — it is not the deferred programmatic fresh-sibling-minting capability.)
184
- - **Enforcement:** non-garden id under `--entwurf-control` → loud stderr + notify + `process.exit(1)` at `session_start`, **before any model turn**. A bare `throw` / `ctx.shutdown()` there is swallowed by pi's runner (verified: the turn ran, 26k tokens leaked), so the guard hard-exits. No uuid / back-compat path — "보이면 바로 터진다".
185
- - **Status label = 🪛 (the forged screwdriver, the North Star), NOT the word "entwurf".** `🪛 ready` before the first assistant turn (file not on disk → model changeable), `🪛 <gardenId>` after (file written → model locked). The id's presence is the model-lock lifecycle signal.
186
- - **Resident name is lazy + `control`-tagged, never `entwurf` — with one sessionId-bound exception.** Set on the first turn via `pi.setSessionName(buildGardenSessionName(...))`. `buildGardenSessionName` is registry-FREE and FORBIDS the `entwurf` tag — the `entwurf` tag is the v2 resume resident marker, so an **operator** resident must never carry it (else a general operator session becomes resumable as a child). The narrow exception: a **v2 spawn-bg authorized Entwurf child** — marked by env `ENTWURF_V2_RESUME_RESIDENT_SESSION_ID` (sessionId-bound) — **keeps** its `entwurf`-tagged name and stays re-resumable when it dies. Only that marker-authorized child is exempt. Gates: `check-entwurf-session-identity` (deterministic) + the v2 child exception via `check-entwurf-v2-spawn-production` + `smoke-entwurf-v2-spawn-resume-live`.
178
+ ### Resident identity — the record is the address (#50 C2)
179
+
180
+ A `--entwurf-control` session is a garden citizen because it has a **meta-record**, not
181
+ because its session id has a particular shape. pi mints its own id (a uuidv7 is normal);
182
+ `birthPiCitizen` upserts `(backend:"pi", nativeSessionId)` at `session_start`, the record
183
+ mints the `gardenId`, and everything addressable hangs off that one string.
184
+
185
+ - **Launch:** `pi --entwurf-control …`. No `--session-id` injection — that was the old
186
+ launcher's job and it is gone, together with `run.sh new-session-id`'s role in launching
187
+ (the generator itself stays; the record uses it to mint garden ids).
188
+ - **In-process new/resume:** pi's own. `/new`, `/fork`, `/clone` and RPC session replacement
189
+ all just fire `session_start`, which attaches the new session as its own citizen and
190
+ rebinds the socket to its address. The `/gnew` command, the pre-switch cancels and the
191
+ garden-format hard exit are deleted — there is no id to police (LOCKED PROTOCOL 2).
192
+ - **Socket:** `~/.pi/entwurf-control/<gardenId>.sock`, keyed on the RECORD's id. A socket
193
+ carrying pi's session id is the pre-cut address and a gate failure.
194
+ - **`PI_SESSION_ID`** carries the gardenId, so every child MCP process reads back a
195
+ routable address (`entwurf_self`), never pi's internal id.
196
+ - **Failure is loud, not cosmetic:** if the record cannot be written (unreadable store,
197
+ duplicate native id, an unreadable store naming the fresh-cut verb) the control server is
198
+ refused, `PI_SESSION_ID` stays unset, and the reason is on stderr. An unaddressable
199
+ resident must not survive quietly — that is the guard's surviving purpose.
200
+ - **Status label = 🪛 (the forged screwdriver, the North Star), NOT the word "entwurf".**
201
+ `🪛 ready` before the first assistant turn (session file not on disk → model changeable),
202
+ `🪛 <gardenId>` after (file written → model locked).
203
+ - **The resident session NAME is pi's.** The `control`-tagged garden name mirror, its
204
+ `entwurf`-tag refusal and the sessionId-bound resume-marker exemption are gone with the id
205
+ they mirrored. Dormant-resume authorization is record existence (LOCKED PROTOCOL 6) plus
206
+ the transcript-header ↔ `record.nativeSessionId` integrity check (#50 C3).
207
+ - Gates: `smoke-pi-attach` (deterministic, in `pnpm check`: record birth · record-keyed
208
+ socket · attach-on-reopen · artifact delivers to the socket) + `smoke-resident-garden-guard`
209
+ (LIVE, the same contract driven through a real `pi` process).
187
210
 
188
211
  ### Send-is-throw
189
212
 
@@ -199,18 +222,18 @@ Messages are thrown, not awaited.
199
222
  |------|---------|
200
223
  | `pi-extensions/acp-provider.ts` | ACP plugin entry: registers the package provider `entwurf` + curated Claude model surface; wires `streamSimple` to the real ACP backend |
201
224
  | `pi-extensions/lib/acp/*.ts` | ACP plugin internals: curated Claude surface + no-auth sentinel (`models.ts`), Claude config overlay (`overlay.ts`), tool surface + exclude-tools preflight (`tool-surface.ts`), ACP→pi event mapper (`event-mapper.ts`), pi Context→ACP prompt (`context.ts`), spawn-per-turn `streamSimple` backend (`backend.ts`) |
202
- | `pi-extensions/entwurf-control.ts` | control plane: `--entwurf-control` socket, RPC, `entwurf_v2` / `entwurf_peers` tools, `/entwurf-sessions` / `/gnew` |
225
+ | `pi-extensions/entwurf-control.ts` | control plane: record attach at session_start, `--entwurf-control` socket (keyed on the record gardenId), RPC, `entwurf_v2` / `entwurf_peers` tools |
226
+ | `pi-extensions/lib/pi-citizen-birth.ts` | the #50 C2 attach seam: pi session → meta-record upsert → control-socket address |
203
227
  | `pi-extensions/model-lock.ts` | package-provider model lock (pi.extension) |
204
228
  | `pi-extensions/meta-bridge-hook.ts` | Claude Code `SessionStart` hook: register a mailbox-backed garden meta-session |
205
- | `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / native-push / runner / production / surface / spawn(+production) + resume-marker |
229
+ | `pi-extensions/lib/entwurf-v2-*.ts` | v2 substrate: contract / lock / decider / matrix / release / send / mailbox / native-push / runner / production / surface / spawn(+production) |
206
230
  | `pi-extensions/lib/native-push/` | Antigravity adapter probe/route, direct-inject hand, explicit native registration core |
207
- | `pi-extensions/lib/meta-*.ts` | meta-record authority, mailbox state, dual-read/migration, receiver/sender identity |
231
+ | `pi-extensions/lib/meta-*.ts` | V3-only meta-record authority (`meta-session.ts`), mailbox state, receiver/sender identity — one live schema, no legacy readers |
208
232
  | `scripts/agy-{bridge,statusline-bridge,hooks-bridge}.*` | three state-backed agy install/doctor/inverse surfaces |
209
233
  | `scripts/agy-imprint.ts` | agy `PreInvocation` automatic birth + record-backed sender marker |
210
234
  | `pi-extensions/lib/entwurf-core.ts` | shared core (session-file lookup, identity read, explicit-extension args); some v1 exports now dead pending routing cleanup |
211
235
  | `protocol.js` | dependency-free shared wire constants (`<project-context` marker); single source for tsc emit + strip-types MCP paths |
212
236
  | `run.sh` | install (incl. `install-meta-bridge`), check-*/smoke-* gates, release-gate |
213
- | `pi/entwurf-targets.json` | spawn-bg resume target allowlist |
214
237
  | `mcp/entwurf-bridge/` | MCP server exposing `entwurf_v2`, `entwurf_self`, `entwurf_peers`, `entwurf_inbox_read` |
215
238
 
216
239
  ## Typecheck Boundary
@@ -234,14 +257,19 @@ Code-level invariants pinned at the same time:
234
257
 
235
258
  ## Runtime Dependencies
236
259
 
237
- - `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.54.1`), `@agentclientprotocol/sdk` (`1.1.0`), `@anthropic-ai/sdk` (`0.100.1`). Codex/Gemini ACP packages stay out of scope; Codex is native/probe, agy is the shipped native-push Google lane, and Gemini ACP remains compatibility history rather than a current target.
238
- - `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.80.7 < 0.81` — devDep exact `0.80.7` + next-minor ceiling). Mismatches are caught by `check-dep-versions` / `check-pi-runtime-version`. 0.80 moved the standalone root `getModels()` to the deprecated `@earendil-works/pi-ai/compat` entrypoint; the curated Claude surface (`pi-extensions/lib/acp/models.ts`) imports `getModels` from `/compat` — the single subpath allowlisted in `check-pi-import-surface`. NOT the 0.80 provider-factory `providers/anthropic` subpath: although it typechecks, pi's extension loader (jiti alias map in pi-coding-agent `core/extensions/loader.ts`) resolves only the bare root, `/compat`, and `/oauth` for extensions — a `providers/*` import resolves to the unresolvable `dist/compat.js/providers/…` and crashes extension load (caught live by `smoke-resident-garden-guard`, not by static typecheck). This `/compat` use is an **extension-loader compatibility shim** chosen by loader constraint, not a preference for a deprecated API — the `<0.81` ceiling guards it; when 0.81 changes `compat` or the loader alias map, re-evaluate against whatever root/loader surface 0.81 then exposes.
260
+ - `@modelcontextprotocol/sdk` and `zod` are the substrate runtime deps. With the Claude-first ACP plugin shipped, the Claude/ACP backend deps are pinned alongside them: `@agentclientprotocol/claude-agent-acp` (`0.61.0`), `@agentclientprotocol/sdk` (`1.3.0`), `@anthropic-ai/sdk` (`0.100.1` — kept: `claude-agent-sdk@0.3.217`'s peer floor is `>=0.93.0`, so 0.100.1 satisfies it and a mechanical rise to the newest SDK is NOT taken). Codex/Gemini ACP packages stay out of scope; Codex is native/probe, agy is the shipped native-push Google lane, and Gemini ACP remains compatibility history rather than a current target.
261
+ - `pi` (`@earendil-works/pi-ai`) on PATH at the pinned range (`>= 0.82.0 < 0.83` — devDep exact `0.82.0` + next-minor ceiling). Mismatches are caught by `check-dep-versions` / `check-pi-runtime-version`. 0.80 moved the standalone root `getModels()` to the deprecated `@earendil-works/pi-ai/compat` entrypoint; the curated Claude surface (`pi-extensions/lib/acp/models.ts`) imports `getModels` from `/compat` — the single subpath allowlisted in `check-pi-import-surface`. NOT a provider-factory subpath such as `providers/anthropic`: although it typechecks, pi's extension loader (jiti alias map in pi-coding-agent `core/extensions/loader.ts`) resolves only FOUR pi-ai specifiers for extensions — the bare root, `/compat`, `/oauth`, and (added in 0.81) `/providers/all` — so any other `providers/*` import resolves to the unresolvable `dist/compat.js/providers/…` and crashes extension load (caught live by `smoke-resident-garden-guard`, not by static typecheck). This `/compat` use is an **extension-loader compatibility shim** chosen by loader constraint, not a preference for a deprecated API — the `<0.83` ceiling guards it.
262
+ - **The re-evaluation this line demanded has been done (2026-07-24, pi `v0.80.7..v0.82.0` source-diffed + both versions installed and `getModels("anthropic")` compared).** The shim holds: root / `/compat` / `/oauth` are untouched in the alias map, `getModels` is still exported from `/compat` (as `getBuiltinModels`, deprecation text now pointing at `/providers/all`), and the curated anchors are byte-identical across the bump (14 models, `claude-opus-4-8` + `claude-sonnet-5`, same `cost` / `contextWindow` / `maxTokens` / `reasoning`). What 0.81 ADDED — the `/providers/all` alias and native `registerProvider(provider)` registration — is a new surface, not a replacement forced on us; migrating the curated read off deprecated `/compat` onto it is a **separate cut**, deliberately kept out of the version bump. Re-evaluate again at the `<0.83` ceiling.
239
263
 
240
264
  ## Working Style
241
265
 
242
266
  - Surgical changes. One thing at a time.
243
267
  - Ask: does this belong in pi? In the resident's own repo? Or here?
244
268
  - Removal on this branch is gate-verified: subtract source AND its gate/case/script together (the 결합 규칙) so `pnpm check` stays green and never goes silently red.
269
+ - **Every repair/removal commit hunts the sentences it invalidated** — adding the new fact without deleting the old claim has now shipped **eight** times (dead registry link → stale NEXT diagnosis → A1/launcher prose surviving C4 → `docs/setup-clean-host.md` teaching the deleted `--session-id` launcher *and a hard-exit guard that no longer exists* → the `shouldListAsLive` removal leaving its own policy sentences behind → the store-doctor claiming dual-read three cuts after V3-only · a gate header claiming v2 writes → **the schema module itself: `MetaIdentity`/serializer/minter/`decideUpsert` doc comments calling the live v3 shape "v2", one of them defaulting a field #50 deleted, while the same function's body comment was already correct**). **Stop extending the directory list — that is what failed three rounds running (`docs/`, then `scripts/`, then the lib the cut actually rewrote).** The unit is the REPO, and the sweep is a method, two axes:
270
+ 1. **Retired vocabulary → repo-wide grep.** Before committing, write down what the cut retired: deleted symbol names, the schema/authority words it demoted (`dual-read`, `v2 identity`, `socketOnly`), the command form it replaced. `grep -rn` each across the whole tree (not only touched files — a schema cut invalidates prose in consumers it never edits), then judge every hit: a *tombstone* ("`X` is GONE since #50") is the goal, a *live claim* ("`X` reads v1 AND v2") is the defect.
271
+ 2. **Landed plans → future-tense grep.** A cut that LANDS invalidates its own plan sentences: `yet` · `not here` · `Today …` · `does NOT yet` · `lands in step N` · `will land`. Staged-build headers are written in future tense and nobody returns to them when the step ships.
272
+ Surfaces to cover at minimum: README · AGENTS · DELIVERY · VERIFY · ROADMAP · `docs/**` (an install walkthrough is a new host's first surface, so a stale command there costs more than a stale README line) · run.sh usage lines AND dispatch/function comments · `scripts/**` operator & gate scripts · **the module the cut rewrote, all of it — being the file you edited is not evidence its other 40 comments were read**. A deleted symbol's *prose* is not deleted by the compiler or by biome — only by this sweep.
245
273
  - Keep docs calibrated: strong language is fine; unbacked language is not.
246
274
  - Resist the urge to make the substrate more magical than necessary.
247
275
 
package/BASELINE.md CHANGED
@@ -24,8 +24,8 @@ host into a certified one.
24
24
  | Node 24 Linux package consumer | Required `artifact-consumer` CI: read-only candidate `.tgz`, checkout-invisible, non-root global install, PATH shims, frozen package root, path+sha256 regular-file fence, strict doctor fixture | None required for the package layout itself | Package-consumer shape verified. The planted Claude cache/owner/bridge are synthetic and prove no real Claude lifecycle. |
25
25
  | Claude Code 2.1.217 exec form | `check-hook-launch-topology` + `check-claude-floor-coherence`; doctor oracle healthy fixture + 21 defect mutations | B2 actual Claude session on NixOS: args per element, literal `${HOME}`, direct parent, FileChanged exit 2 → idle wake | Runtime behavior verified at 2.1.217 on one host; this is the supported floor. |
26
26
  | Claude Code 2.1.138 negative | Launcher empty-argv refusal + installer/doctor floor checks | B actual Claude session on NixOS: args discarded while runtime reported success | Unsupported; no shell-form fallback. |
27
- | Maintainer NixOS installed package | Gates and B/B2 are green, but the installed artifact is intentionally stale before release | Post-release clean reinstall → new Claude session → installed doctor exit 0 **pending** | Not yet host-certified for the repair artifact. |
28
- | hejdev6 Ubuntu installed package | Linux artifact-consumer gate models the package shape, not this machine | Post-release clean reinstall → new Claude session → installed doctor exit 0 **pending** | Recovery remains open; hand-patched hooks and validate output are not acceptance. |
27
+ | Maintainer NixOS installed package | Gates and B/B2 are green; the published `0.12.8-repair.1` artifact was installed from the registry for acceptance, then the V3 development wiring was restored | 2026-07-25: registry install → installed `install-meta-bridge` → NEW Claude session with a live MCP child → installed doctor **exit 0** (HISTORY) | Host-certified for the published repair artifact, including physical `entwurf_v2` delivery and the live owner join. The doctor first went RED on a managed dev-bin shadowing the registry bridge. This host now runs dev wiring again; stable `0.12.8` earns its own host proof. |
28
+ | Secondary Ubuntu Linux installed package | Linux artifact-consumer gate models the package shape, not this machine | 2026-07-25: same registry artifact, isolated clean `PI_CODING_AGENT_DIR`, NEW Claude session with a live MCP child → installed doctor **exit 0** (HISTORY) | Recovery closed for `0.12.8-repair.1`. Hand-patched hooks and validate output remain non-acceptance; a stable artifact is a separate proof. |
29
29
  | macOS Claude meta-bridge | No artifact-consumer job and no `/proc` live join | None | **Not yet verified/certified for this repair cut.** Installer refuses Darwin and doctor remains nonzero; uninstall permits Darwin to remove older managed state. This is not permanent—future native validation may reopen it, and package-level `os` stays unrestricted. |
30
30
  | WSL2 / Windows | None | None | Unverified / outside this repair cut. |
31
31
 
@@ -274,6 +274,89 @@ prompt, and if so quote the visible text exactly:
274
274
 
275
275
  # HISTORY (pointer)
276
276
 
277
+ 2026-07-25 repair.1 installed-native host acceptance (stable-promotion prerequisite):
278
+ the published registry artifact `@junghanacs/entwurf@0.12.8-repair.1` was installed
279
+ fresh on two Linux hosts (maintainer + secondary) through the package's stable bins.
280
+ Each host ran installed `entwurf install-meta-bridge`, opened a NEW real Claude Code
281
+ session with a live MCP child, and ran the installed `entwurf doctor-meta-bridge`
282
+ against an isolated clean `PI_CODING_AGENT_DIR`; both doctors reached **PASS**, including
283
+ the live MCP owner join and a physical `entwurf_v2` delivery. The maintainer host first
284
+ proved the oracle's value by failing when its managed dev-bin shadowed the registry
285
+ `entwurf-bridge`: the installed v2 hook wrote a v2 record while the checkout's v3 bridge
286
+ refused it. Removing the managed dev bin made PATH resolve the registry bridge, after
287
+ which the same native proof passed. The test-created v2 record from that failed mixed-path
288
+ attempt was preserved under `meta-sessions.proof-failed-20260725T165227/`; the maintainer's
289
+ V3 development wiring was restored after acceptance. This closes VERIFY's two-host
290
+ repair.1 prerequisite for a separately authorized stable `0.12.8`; it is host
291
+ corroboration of the published repair artifact, not evidence for the future stable
292
+ candidate, which still earns exact-SHA CI, LIVE, and preserved-artifact acceptance.
293
+ Exact pre-version closure checkpoint `28a52fe2d6e9ca29b657a33e5c80ff4debda2f0f`
294
+ passed GitHub Actions run [30149759311](https://github.com/junghan0611/entwurf/actions/runs/30149759311):
295
+ `check`, `install-surface`, and `artifact-consumer` all success. The host proof then found
296
+ a one-line `remove-dev-bin` dispatch defect, so the eventual stable landing HEAD must earn
297
+ a fresh exact-SHA run; this checkpoint is not reused as that acceptance.
298
+
299
+ 2026-07-24 (night) upgrade-harness + review acceptance at exact HEAD
300
+ `cbda097` (branch `repair/v2-core-debt`, merged to main the same night — the
301
+ hard-cut branch chronicle lives in issue #50): the three-cell harness gained
302
+ the UPGRADE axis — `setup` / `install` / `install-meta-bridge` refuse a
303
+ pre-cut (v1/v2) meta-record store BEFORE their first write, prescribe on
304
+ three axes (pre-cut → migrate; problems → repair first; both → repair FIRST,
305
+ then migrate), and the proof seeds every host state from frozen fixture bytes
306
+ (`fixtures/meta-store`, sha256-manifested, excluded from the tarball).
307
+ Deterministic cells at this HEAD: `pnpm check` EXIT=0 (source cell
308
+ `check-upgrade-gate` 57/0), `check-pack-install` EXIT=0,
309
+ `ENTWURF_REQUIRE_DOCKER=1 check-install-container` EXIT=0 — candidate
310
+ `junghanacs-entwurf-0.12.8-repair.1.tgz` **sha256
311
+ `db17165f962c938d71ef97cb7a86252549dc91b00d5ec67f63ec65b41039e6dc`**,
312
+ 11413738 bytes, image `sha256:f1158c7f34cf35a047bf0513c38282bb2fa253529e5ae404b32c6d93697410be`.
313
+ Live at this HEAD: `LIVE=1 release-gate` **MUST 16/1/0 + BEHAVIOR 1/0,
314
+ EXIT=1** — the single FAIL is `smoke-acp-bundled-mcp-live`, the known
315
+ bundled-MCP readiness race (ROADMAP 「🔴 OPEN」, GLG: observe, don't fix;
316
+ sample recorded with transcript; isolated re-run PASS 4/4). Every other MUST
317
+ passed at this HEAD, including `smoke-acp-v2-send-live` (send identity /
318
+ replyability) and the matrix honest-reject. **A release cut stays blocked on
319
+ that red by the gate's own words; the merge to main was GLG's explicit call
320
+ with the race documented as an open observation item.**
321
+
322
+ 2026-07-24 dependency-uplift acceptance at exact HEAD
323
+ `7cbeb29b6afcfbaf4fc28da3b7929037c339113d` (branch `repair/v2-core-debt`): pi
324
+ runtime **0.80.7 → 0.82.0** and Claude ACP **claude-agent-acp 0.54.1 → 0.61.0 /
325
+ ACP SDK 1.1.0 → 1.3.0** as two separate cuts, with `@anthropic-ai/sdk` held at
326
+ **0.100.1** (measured through the real module graph: claude-agent-sdk 0.3.217's
327
+ `>=0.93.0` peer resolves to 0.100.1 there; dropping the direct pin under this
328
+ repo's `autoInstallPeers:false` leaves only 0.91.1 and the peer goes unmet).
329
+ Deterministic 3 cells all EXIT=0 on Node 24 Linux — checkout (`pnpm
330
+ build-bridge && pnpm check`), installed tree (`check-pack-install`: resolved
331
+ tree holds only `@earendil-works@0.82.0`, loader drove the pinned pi, installed
332
+ bin delivered a `.msg`), clean consumer (`ENTWURF_REQUIRE_DOCKER=1
333
+ check-install-container`, candidate `junghanacs-entwurf-0.12.8-repair.1.tgz`
334
+ **sha256 `ab5dee07585c8d7a4f8f174cedea0051489ae1a26766ff1baf8edd7377d5bac7`**,
335
+ 11391060 bytes, image `sha256:f1158c7f34cf35a047bf0513c38282bb2fa253529e5ae404b32c6d93697410be`).
336
+ Live: `LIVE=1 ./run.sh release-gate` measured **MUST 17/0/0 + BEHAVIOR 1/0,
337
+ EXIT=0** at this HEAD — the first aggregate to include
338
+ `smoke-acp-v2-send-live`, which closes the SEND half of ACP citizenship (an ACP
339
+ model calls `entwurf_v2` and the `.msg` lands carrying the resident's own garden
340
+ id, `entwurf/<model>`, replyable — a gid never present in the prompt). Two
341
+ stale claims were retired against measurement rather than argument: the
342
+ extension-loader `/compat` shim survives 0.82.0 (root / `/compat` / `/oauth`
343
+ untouched; `/providers/all` is an addition, and the curated Claude anchors are
344
+ byte-identical across the bump), and the "one-shot bundled-MCP teardown hang"
345
+ that a gate comment used as its rationale does not reproduce on this
346
+ combination. What a plain `pi -p` genuinely lacks is garden identity, and only
347
+ without `--entwurf-control` — now documented as a provider/citizen boundary
348
+ instead of read as a defect.
349
+
350
+ 2026-07-24 record-era aggregate floor: `LIVE=1 ./run.sh release-gate` measured
351
+ **MUST 16/0/0 + BEHAVIOR 1/0, EXIT=0** on the `repair/v2-core-debt` branch after
352
+ the #50 C1–C3 cuts and the observability repair — the first aggregate run since
353
+ 2026-06-27 (every individual smoke had been green, but the two-tier summary and
354
+ exit code of the aggregate command itself had gone unverified for the whole
355
+ hard-cut window; three MUST live smokes were found dead on the pre-C2 address
356
+ contract and re-authored in the same pass). The step count moved 17→16 with the
357
+ v2-cutover smoke retirements. Evidence log: `/tmp/pi-tmux-release-gate.log`
358
+ (scratch `/tmp/entwurf-rg-scratch-20260724`).
359
+
277
360
  2026-07-22 repair evidence: Linux artifact-consumer C is committed locally as
278
361
  `328c66e` (not yet pushed at the time of this baseline update); B/B2 direct-native
279
362
  observations and the exec-only production cut are documented in issue #51 and
@@ -287,9 +370,14 @@ inode/size/mtime/sha tuple was unchanged across acceptance. Evidence logs:
287
370
  `/tmp/pi-tmux-entwurf-exact-final.log` and
288
371
  `/tmp/pi-tmux-entwurf-default-final.log`; the digest belongs in the external cut log,
289
372
  not inside this shipped file (embedding it would mutate the tarball it names).
290
- This was the current `0.12.7-1` gate candidate, **not** the approved release artifact;
291
- repeat exact mode after the separate `0.12.8-repair.0` version commit. Maintainer/
292
- hejdev6 installed doctor GREEN remains deliberately pending until after release.
373
+ This was the `0.12.7-1` gate candidate, **not** the approved release artifact. Exact
374
+ mode was later repeated for `0.12.8-repair.0`, and those accepted bytes were published
375
+ under `repair` on 2026-07-22. Field evidence then invalidated that release: its installed
376
+ MCP dist omitted `entwurf-capabilities.json`, so tools/list and the old doctor stayed
377
+ green while every `entwurf_v2` send died ENOENT. The repaired candidate must be
378
+ `0.12.8-repair.1` and must earn fresh exact-SHA CI, LIVE-gate, preserved-artifact, and
379
+ container evidence; none of repair.0's release evidence transfers. Maintainer/secondary-host
380
+ installed doctor GREEN remains deliberately pending until after repair.1 publication.
293
381
 
294
382
 
295
383
  Per-release baselines — the 0.9.0 garden-native identity cut (17 PASS / 0 FAIL /
@@ -298,4 +386,4 @@ baselines — live in **CHANGELOG.md and git history**, including the gate names
298
386
  their era (several of which, e.g. `smoke-all` / `smoke-async-resume` /
299
387
  `smoke-compaction-policy` / `sentinel` / `xt-tool-surface`, were retired in the
300
388
  v2 cutover). The live calibration reference is the current release floor in
301
- [VERIFY.md](./VERIFY.md) §0A — most recent: **2026-06-27 MUST 17/0/0 + BEHAVIOR 1/0**.
389
+ [VERIFY.md](./VERIFY.md) §0A — most recent: **2026-07-24 MUST 16/0/0 + BEHAVIOR 1/0**.
package/CHANGELOG.md CHANGED
@@ -4,6 +4,49 @@ All notable changes to this project will be documented here. Format follows [Kee
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ## 0.12.8 — 2026-07-25
8
+
9
+ ### Changed
10
+
11
+ - **ACTION REQUIRED — hosts carrying a pre-v3 meta-record store refuse install and every identity write until an explicit generation cut.** The active citizen store is v3-only and carries no cross-generation address or resume continuity: sessions flow; memory lives in native transcripts and the embedding axes, never in the bridge. `install` / `setup` / citizen birth / `entwurf_register_native` refuse before writing when the store cannot certify and name the one repair verb: quiesce sessions, run `entwurf meta-bridge-fresh-cut` (dev clone: `./run.sh meta-bridge-fresh-cut`), then retry. The cut archives `meta-sessions/` + `meta-mailbox/` as forensic siblings and opens an empty v3 generation; no runtime reads the archive and no restore verb exists.
12
+ - **#50 hard cut: the meta-record is the only address authority.** V3 drops `parentGardenId` + `isEntwurf`, removes the v1 `entwurf` / `entwurf_resume` / `entwurf_send` tools and `/entwurf*` commands, deletes `pi/entwurf-targets.json` + `setup:links`, and authorizes dormant resume through record existence plus transcript-header ↔ `record.nativeSessionId` integrity. A call is not parentage and there is no species boolean.
13
+ - **The migration lane is deleted, not deprecated.** `meta-migration.ts`, the M1 backup/migrate/restore command, three gates (`check-meta-migrate-v3`, `check-meta-migration-readers`, `check-upgrade-gate`), and the frozen byte fixtures — 2,404 lines of deleted files, for continuity the substrate does not promise — are replaced by one generation verb (`meta-bridge-fresh-cut`) and one writer/doctor contract (`certifyActiveStore`). The whole upgrade story is quiesce → fresh-cut → go.
14
+ - **The runtime pins move together.** Pi rises 0.80.7 → 0.82.0 under the closed peer range and doc gates; Claude ACP rises to `@agentclientprotocol/claude-agent-acp 0.61.0` + `@agentclientprotocol/sdk 1.3.0`, with `@anthropic-ai/sdk 0.100.1` retained. The ACP send gate proves a provider model can send as its host socket-citizen.
15
+
16
+ ### Fixed
17
+
18
+ - **One active-store contract is shared by the doctor and every identity writer.** `certifyActiveStore` requires each `.meta.json` to be a regular file, readable by the live schema, named by its own body, and the unique holder of its `nativeSessionId`; it runs store-wide before every identity write. Targeted reads enforce the per-entry half and never follow a symlink. Duplicate uniqueness on read/discovery remains tracked separately in #52.
19
+ - **Unknown is never silently converted to absent or dead on the fresh-cut path.** ENOENT alone means absence across record, store, directory and socket-entry inspection; EACCES/ENOTDIR/ELOOP and symlink/non-directory surfaces refuse as UNCERTAIN. The quiesce gate also probes marker-less native-push citizens through the same adapter dispatch uses, and `pgrep` exit 1 alone means no host while scan failures stay indeterminate. Five directory inputs across four code paths and the socket-entry layer are covered by F12–F18.
20
+ - **The archive plan refuses common half-cut causes before moving and reports every partial move honestly.** Store and mailbox may have different parents, so each planned rename preflights parent writability and every destination is inspected with ENOENT-only absence before the first move. No permission probe can promise a rename (sticky bit, immutable attributes, read-only mounts and LSMs remain possible); if a rename fails, the loop prints each `archived so far:` path, calls the generation HALF-CUT, and gives the exact retry/manual-inspection prescription.
21
+ - **Only a doctor verdict earns a destructive prescription.** Both store-doctor callers map exit 1 to certification defects → fresh-cut and exit 3 to access repair; usage, crash and unknown exits are doctor/runtime failures and prescribe no cut. `run.sh` also guards the actual doctor entry selected by its mode (source `.ts` vs installed compiled `.js`), so a missing artifact cannot collide with the doctor's defect exit. I7–I9 drive both callers and the installed-artifact seam.
22
+ - **The installed-host acceptance closed two operator/test seams.** `./run.sh remove-dev-bin` now shifts its own command name before invoking the honest inverse. Stable-bin smokes remove every pre-existing provider/statusline bin directory from their sandbox PATH, so a maintainer carrying both dev links and registry shims cannot mask a dangling-command negative.
23
+
24
+ ### Carried from the repair line
25
+
26
+ - Exec-form Claude hooks + the enforced Claude Code `>=2.1.217` floor (repair.0), and the capability registry beside the emitted MCP bridge with live-command physical delivery in `doctor-meta-bridge` (repair.1), are promoted to `latest`. After publication the required registry shape is `latest=0.12.8`, `repair=0.12.8-repair.1`.
27
+
28
+ ### Verification
29
+
30
+ - 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
+ - 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
+ - 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`.
34
+
35
+ ## 0.12.8-repair.1 — 2026-07-22
36
+
37
+ ### Fixed
38
+
39
+ - **ACTION REQUIRED — `0.12.8-repair.0` is published but cannot deliver to mailbox-backed garden citizens.** Its npm tarball contains the source capability registry but omits the copy beside the emitted MCP bridge, so the installed `entwurf-bridge` boots and answers `tools/list` while a real `entwurf_v2` delivery dies `ENOENT …/entwurf-capabilities.json`. The same omission exists in `latest=0.12.7`; this cut deliberately moves only the `repair` dist-tag, leaving stable promotion for a separately authorized `0.12.8` after post-publish host proof. Install this exact repair, rerun `entwurf install-meta-bridge`, restart every already-open Claude Code session, open a new session with its live MCP child, and require the installed `entwurf doctor-meta-bridge` to exit 0. The doctor now proves delivery, not merely configuration shape.
40
+ - **The shipped MCP dist now carries the capability registry at the location its emitted `meta-session.js` actually resolves.** `build-bridge.sh` copies `pi/entwurf-capabilities.json` to `mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json`; this is the bundle-root contract already used by the Claude meta-bridge plugin. `check-capability-bundle-reach` discovers every shipped `meta-session` copy, asks each copy from its real location, requires byte agreement with the source registry, and drives `metaCapabilityFor()` for all four registered backends. `check-bridge-delivery` then seeds isolated sender/receiver citizens, starts the built dist entry as a separate MCP stdio process, calls `entwurf_v2`, and requires one `.msg`, the doorbell, the seeded sender envelope, and no capability ENOENT. The same scene is replayed against `check-pack-install`'s project-local npm-installed bin and the clean Linux consumer's non-root global PATH shim, so source, dist, installed tree, and checkout-invisible consumer no longer split “boots” from “delivers.” This restores the fire-and-forget mailbox lane; it does not claim the separate neutral-install dormant-pi `owned-outcome` follow-up is solved.
41
+ - **`doctor-meta-bridge` now drives the live MCP command Claude is configured to execute and requires a physical delivery in a throwaway world.** Ownership and behavior remain separate verdicts: the live `~/.claude.json` entry must equal `desired_mcp()`, and that exact live command—not a recomputed healthy command—must land one message and poke its doorbell. The probe redirects `PI_CODING_AGENT_DIR`, every meta store, and the socket root; no model, network, API cost, or operator mailbox is involved. Oracle mutations cover an absent live entry and a registry-less bundle that still answers `tools/list`, while the container mutation removes the registry only from the global install and proves every other doctor claim stays green as delivery alone turns red.
42
+ - **Delivery verification no longer changes identity depending on which harness runs it.** A pi-launched doctor inherited `PI_SESSION_ID` plus `PI_AGENT_ID`; the bridge chooses that pair before meta-sender discovery, so the message still landed while the claimed seeded Claude sender-marker join was silently bypassed. The doctor and deterministic delivery gate now scrub both pi carriers plus `ENTWURF_META_SENDER_MARKER`, require `ENTWURF_BRIDGE_REQUIRE_META_SENDER=1`, and inspect the landed body for the seeded `meta-session/claude-code` garden id. A planted ambient pi pair and explicit marker carrier are part of the control; deleting the scrub leaves physical delivery green but turns the sender assertion red.
43
+ - **The repair publication check is bound to the requested version instead of the already-published repair.0 literal.** The shared release skill now compares the registry's `repair` tag with `$VERSION`, while preserving the current contract that `latest` stays `0.12.7`; without this correction a successful repair.1 `npm publish` would have been followed by a false post-publish failure. The S7 install-surface gate binds the skill to SemVer prerelease syntax rather than to one obsolete example version.
44
+
45
+ ### Verification
46
+
47
+ - Pre-version landing HEAD `4ae5aa874886fc889c0525369b5290066b6f96af` passed exact-SHA GitHub Actions run [29919713499](https://github.com/junghan0611/entwurf/actions/runs/29919713499): `check`, `install-surface`, and `artifact-consumer` all concluded success.
48
+ - On the repair.1 prepared working tree, `pnpm check` passed and `LIVE=1 ./run.sh release-gate /tmp/entwurf-release-gate-0.12.8-repair.1.81GJe3` completed with `MUST: PASS=17 FAIL=0 SKIP=0` and advisory `BEHAVIOR: PASS=1 FAIL=0`; full log: `/tmp/entwurf-release-gate-0.12.8-repair.1.81GJe3/release-gate.log`. The final preserved tarball, prepared-HEAD exact-SHA CI, container acceptance, tag, and GitHub release remain deliberately deferred to `make`; no candidate was created in prepare.
49
+
7
50
  ## 0.12.8-repair.0 — 2026-07-22
8
51
 
9
52
  ### Fixed
@@ -99,7 +142,7 @@ All notable changes to this project will be documented here. Format follows [Kee
99
142
  - `pnpm check` passed on 2026-07-01 after the doctor/install-floor fix.
100
143
  - `./run.sh check-pack-install` passed with the new installed store-doctor scan and doctor-dispatch lock assertions.
101
144
  - Release-gate prep evidence: `LIVE=1 ./run.sh release-gate /tmp/psa-release-gate-0.12.4.PliLsd` passed on 2026-07-01; log `/tmp/pi-tmux-entwurf-release-gate-0124.log`; summary `MUST: PASS=17 FAIL=0 SKIP=0`, advisory `BEHAVIOR: PASS=0 FAIL=1` (`smoke-resident-garden-guard` post-`/gnew` autonomous `entwurf_self` identity turn; non-blocking).
102
- - `hejdev6` real floor host reproduced the pre-fix strip-types failure from an installed package and passed after installing the patched tarball: compiled store-doctor scanned `1 record(s)` with plain `node`, and installed `doctor-meta-bridge` reported store-scan ok plus v2-surface deferred.
145
+ - `target Linux host` real floor host reproduced the pre-fix strip-types failure from an installed package and passed after installing the patched tarball: compiled store-doctor scanned `1 record(s)` with plain `node`, and installed `doctor-meta-bridge` reported store-scan ok plus v2-surface deferred.
103
146
 
104
147
  ## 0.12.3 — 2026-07-01
105
148
 
@@ -141,7 +184,7 @@ All notable changes to this project will be documented here. Format follows [Kee
141
184
  - `pnpm check` passes with the new `check-meta-manifest-schema` static guard included.
142
185
  - `./run.sh smoke-meta-install-state` passes, proving the state manager/doctor consumers still follow `desired_mcp()` without drift.
143
186
  - Installed-location regression probe passes: running `scripts/check-meta-manifest-schema.py` from a synthetic `node_modules/@junghanacs/entwurf` package no longer self-fails.
144
- - Claude Code 2.1.97 floor validation passed on `hejdev6` after removing the root marketplace `description`; current Claude 2.1.195 validation also passes with warnings only.
187
+ - Claude Code 2.1.97 floor validation passed on `target Linux host` after removing the root marketplace `description`; current Claude 2.1.195 validation also passes with warnings only.
145
188
  - `LIVE=1 ./run.sh release-gate /tmp/psa-release-gate-0.12.2.NLGhet` passed on 2026-06-29 with `MUST: PASS=17 FAIL=0 SKIP=0` and `BEHAVIOR: PASS=1 FAIL=0`; log `/tmp/entwurf-release-gate-0.12.2-20260629T205339.log`.
146
189
 
147
190
  ## 0.12.1 — 2026-06-29
@@ -162,7 +205,7 @@ All notable changes to this project will be documented here. Format follows [Kee
162
205
  ### Verification
163
206
 
164
207
  - `./run.sh check-pack-install` passes with the neutral npm install regression: package bins present, optional pi peers absent, installed dist bridge answers `tools/list`, and pi-loader registration still passes on the explicit pi-peer lane.
165
- - Remote `hejdev6` real-install probe from the packed tarball passed: local npm install, package bins, optional pi peers absent, installed `entwurf-bridge` `tools/list`, `entwurf install` with isolated HOME, and `entwurf check-bridge`. The host's real HOME also exposed a pre-existing stale `~/.pi/agent/entwurf-targets.json` symlink to `pi-shell-acp`; fix with `entwurf setup:links --force` or an explicit `ENTWURF_TARGETS_PATH` if that old registry is intentional.
208
+ - Remote `target Linux host` real-install probe from the packed tarball passed: local npm install, package bins, optional pi peers absent, installed `entwurf-bridge` `tools/list`, `entwurf install` with isolated HOME, and `entwurf check-bridge`. The host's real HOME also exposed a pre-existing stale `~/.pi/agent/entwurf-targets.json` symlink to `pi-shell-acp`; fix with `entwurf setup:links --force` or an explicit `ENTWURF_TARGETS_PATH` if that old registry is intentional.
166
209
  - `LIVE=1 ./run.sh release-gate /tmp/psa-release-gate-0.12.1.GUFDUb` tiers `MUST: PASS=17 FAIL=0 SKIP=0` with `BEHAVIOR: PASS=1 FAIL=0` on 2026-06-29; log `/tmp/entwurf-release-gate-0.12.1-20260629T191543.log` (the two live-smoke observation fixes above were what moved the gate from `MUST FAIL=1` to green; the install change is harness-neutral and touches no ACP code path).
167
210
 
168
211
  ## 0.12.0 — 2026-06-29
package/DELIVERY.md CHANGED
@@ -109,8 +109,8 @@ the `D0–D8` capability level:
109
109
 
110
110
  | Harness / surface | Status | Highest current level | Transport | Notes |
111
111
  |---|---|---:|---|---|
112
- | **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session. `entwurf_v2` treats a record-less but live pi control socket as a socket-only `fire-and-forget` target; record-less *dormant* resume is intentionally not claimed. |
113
- | **Claude Code interactive >=2.1.217** | shipped *(Linux is the only certified axis in this repair cut)* | D6, D7 partial, D8 partial | Exec-form global plugin: `SessionStart` arms `watchPaths`; external write triggers exec-form `FileChanged`; `asyncRewake` wakes idle session | B2 direct-native at 2.1.217 on one NixOS host proved per-element argv, no shell expansion, parent join, and exit-2 idle wake. B at 2.1.138 proved the negative: `args` discarded while Claude reported success, so installer/doctor enforce 2.1.217 and there is no shell fallback. The launcher provenance token keeps an old cached command fail-closed. Active idle wake is D6; D7/D8 remain partial as before. The Linux container's planted cache/owner/bridge are fixtures, not a second native-host proof. |
112
+ | **pi native Entwurf** | shipped | D7+ | Unix control socket + pi followUp/custom messages | Replyable pi session. This is the resident baseline, not an external meta-session. The meta-record is the sole address authority (#50 C4): a record-less control socket — live or not — is refused as `record-less-socket` (diagnostic state), never dispatched. |
113
+ | **Claude Code interactive >=2.1.217** | shipped *(Linux is the only certified axis)* | D6, D7 partial, D8 partial | Exec-form global plugin: `SessionStart` arms `watchPaths`; external write triggers exec-form `FileChanged`; `asyncRewake` wakes idle session | B2 direct-native at 2.1.217 on one NixOS host proved per-element argv, no shell expansion, parent join, and exit-2 idle wake. B at 2.1.138 proved the negative: `args` discarded while Claude reported success, so installer/doctor enforce 2.1.217 and there is no shell fallback. The launcher provenance token keeps an old cached command fail-closed. Active idle wake is D6; D7/D8 remain partial as before. The Linux container's planted cache/owner/bridge are fixtures, not a second native-host proof. |
114
114
  | **Antigravity / agy** | shipped | D6, D7 partial | Native LS gRPC `agentapi send-message` (native-push) | `PreInvocation` automatically births/attaches by native `conversationId` and writes the record-backed pid/start-key sender marker; `entwurf_v2` fire-and-forget probes and direct-injects through the antigravity adapter with a one-shot re-probe retry. Three managed adapters own MCP+one exact permission, statusline, and hook separately. `entwurf_register_native` remains an explicit/manual fallback, not the normal birth path. Live sender→sibling→same-gid reply passed on 2026-07-13, re-verified at **agy 1.1.0** on 2026-07-14 (13/13 LIVE checks); D7 stays partial because there is no canonical transcript/content receipt owned by the smoke. |
115
115
  | **Codex app-server-backed TUI 0.136.0** | verified-probe | D6, D7 (status) | WebSocket-over-UDS `turn/start` into the live `threadId` | **Demonstrated, no managed standalone, no cloud.** `codex app-server --listen unix://<owned 0700 dir>` + plain `codex` auto-attach (or `--remote unix://`). Full message injection (agy-like, not a doorbell); `thread/status/changed` gives completion observation. D8 robustness (dedupe / crash recovery / ordering policy) is not tested. `turn/steer` is active-turn steering, not idle wake. |
116
116
  | **Codex embedded TUI 0.136.0** | deferred | D0 partial | Native state DB / rollout transcript only | Standalone Embedded TUI binds no socket; no `FileChanged`/`asyncRewake` in Codex hooks; not retrofittable. Identify-only via state DB / rollout. |