@junghanacs/entwurf 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/AGENTS.md +52 -17
  2. package/BASELINE.md +60 -206
  3. package/CHANGELOG.md +64 -0
  4. package/CONTRIBUTING.md +14 -10
  5. package/DELIVERY.md +118 -261
  6. package/README.md +91 -431
  7. package/VERIFY.md +74 -95
  8. package/demo/README.md +1 -1
  9. package/demo/demo-baseline.sh +1 -3
  10. package/demo/demo.sh +2 -5
  11. package/docs/acp-backend-rail.md +236 -0
  12. package/docs/external-mcp-host.md +131 -0
  13. package/docs/fresh-cut-policy.md +99 -0
  14. package/docs/setup-clean-host.md +124 -328
  15. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +160 -67
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +12 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +11 -10
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +1 -1
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +42 -1
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +4 -4
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +11 -9
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +7 -5
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +13 -14
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +45 -40
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +117 -95
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +23 -57
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +16 -7
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +5 -53
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +21 -36
  30. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -15
  31. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +12 -11
  32. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +2 -7
  33. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +30 -67
  34. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +256 -0
  35. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +91 -5
  36. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +258 -0
  37. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +202 -0
  38. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +289 -0
  39. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +170 -0
  40. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +136 -0
  41. package/mcp/entwurf-bridge/dist/pi-extensions/lib/session-id.js +8 -5
  42. package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +3 -3
  43. package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +51 -0
  44. package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +9 -4
  45. package/mcp/entwurf-bridge/src/index.ts +176 -67
  46. package/mcp/entwurf-bridge/start.sh +2 -2
  47. package/mcp/entwurf-bridge/test.sh +23 -9
  48. package/mcp/entwurf-bridge/tsconfig.build.json +11 -2
  49. package/package.json +25 -11
  50. package/pi-extensions/entwurf-control.ts +220 -71
  51. package/pi-extensions/lib/acp/acp-client.ts +22 -0
  52. package/pi-extensions/lib/acp/augment.ts +42 -3
  53. package/pi-extensions/lib/acp/backend-adapter.ts +12 -11
  54. package/pi-extensions/lib/acp/backend.ts +366 -38
  55. package/pi-extensions/lib/acp/config.ts +1 -1
  56. package/pi-extensions/lib/acp/engraving.ts +43 -1
  57. package/pi-extensions/lib/acp/event-mapper.ts +16 -13
  58. package/pi-extensions/lib/acp/models.ts +4 -4
  59. package/pi-extensions/lib/acp/overlay.ts +11 -9
  60. package/pi-extensions/lib/entwurf-control-rpc.ts +7 -5
  61. package/pi-extensions/lib/entwurf-core.ts +15 -15
  62. package/pi-extensions/lib/entwurf-resume-args.ts +41 -52
  63. package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
  64. package/pi-extensions/lib/entwurf-v2-contract.ts +120 -99
  65. package/pi-extensions/lib/entwurf-v2-decider.ts +30 -91
  66. package/pi-extensions/lib/entwurf-v2-lock.ts +16 -7
  67. package/pi-extensions/lib/entwurf-v2-production.ts +4 -78
  68. package/pi-extensions/lib/entwurf-v2-release.ts +25 -49
  69. package/pi-extensions/lib/entwurf-v2-runner.ts +6 -21
  70. package/pi-extensions/lib/entwurf-v2-send-fallback.ts +12 -11
  71. package/pi-extensions/lib/entwurf-v2-send.ts +2 -7
  72. package/pi-extensions/lib/entwurf-v2-surface.ts +36 -76
  73. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +370 -0
  74. package/pi-extensions/lib/meta-session.ts +93 -5
  75. package/pi-extensions/lib/mux-fresh-call.ts +328 -0
  76. package/pi-extensions/lib/mux-launch.ts +267 -0
  77. package/pi-extensions/lib/mux-placement.ts +387 -0
  78. package/pi-extensions/lib/mux-resume-call.ts +221 -0
  79. package/pi-extensions/lib/resume-launch-identity.ts +162 -0
  80. package/pi-extensions/lib/session-id.js +8 -5
  81. package/pi-extensions/lib/socket-discovery.ts +3 -3
  82. package/prompts/engraving.md +13 -5
  83. package/run.sh +688 -282
  84. package/scripts/agy-bridge-config.py +5 -1
  85. package/scripts/check-acp-backend-preflight.ts +1 -1
  86. package/scripts/check-acp-carrier-augment.ts +246 -10
  87. package/scripts/check-acp-cortex.ts +5 -5
  88. package/scripts/check-acp-overlay.ts +13 -3
  89. package/scripts/check-acp-prompt-lifecycle.ts +565 -0
  90. package/scripts/check-acp-stop-reason.ts +342 -0
  91. package/scripts/check-acp-stream-hooks.ts +504 -0
  92. package/scripts/check-elapsed.sh +25 -0
  93. package/scripts/check-entwurf-bridge-boot.ts +51 -4
  94. package/scripts/check-entwurf-bridge-pi-free.ts +6 -5
  95. package/scripts/check-entwurf-control-rpc.ts +4 -3
  96. package/scripts/check-entwurf-resume-args.ts +72 -70
  97. package/scripts/check-entwurf-session-identity.ts +14 -10
  98. package/scripts/check-entwurf-v2-contract.ts +34 -59
  99. package/scripts/check-entwurf-v2-decider.ts +17 -177
  100. package/scripts/check-entwurf-v2-lock.ts +5 -2
  101. package/scripts/check-entwurf-v2-matrix.ts +3 -53
  102. package/scripts/check-entwurf-v2-production.ts +2 -91
  103. package/scripts/check-entwurf-v2-release.ts +10 -105
  104. package/scripts/check-entwurf-v2-runner.ts +4 -85
  105. package/scripts/check-entwurf-v2-send-fallback.ts +5 -6
  106. package/scripts/check-entwurf-v2-send.ts +0 -28
  107. package/scripts/check-entwurf-v2-surface.ts +198 -128
  108. package/scripts/check-entwurf-v2-visible-resume.ts +445 -0
  109. package/scripts/check-fresh-cut-gate.sh +1 -1
  110. package/scripts/check-gate-qualification.ts +101 -7
  111. package/scripts/check-install-container.sh +10 -2
  112. package/scripts/check-install-surface.ts +1 -1
  113. package/scripts/check-keyset-overlap.py +1 -1
  114. package/scripts/check-meta-facts.ts +249 -0
  115. package/scripts/check-meta-identity-consumers.ts +1 -1
  116. package/scripts/check-meta-session.ts +169 -0
  117. package/scripts/check-mux-launch-tmux.ts +316 -0
  118. package/scripts/check-mux-launch.ts +288 -0
  119. package/scripts/check-mux-launcher-fence.ts +264 -0
  120. package/scripts/check-mux-parent-artifact.ts +195 -0
  121. package/scripts/check-mux-placement-tmux.ts +322 -0
  122. package/scripts/check-mux-placement.ts +323 -0
  123. package/scripts/check-mux-resume-call.ts +282 -0
  124. package/scripts/check-probe-cli-shim.ts +25 -22
  125. package/scripts/check-probe-ordering.ts +121 -81
  126. package/scripts/check-release-gate-outcomes.ts +452 -0
  127. package/scripts/check-resume-launch-identity.ts +244 -0
  128. package/scripts/check-socket-discovery.ts +1 -1
  129. package/scripts/fixtures/mux-parent-transcript.scrubbed.jsonl +3 -0
  130. package/scripts/inventory-verification-surface.ts +349 -0
  131. package/scripts/lib/claude-launcher-fence.ts +322 -0
  132. package/scripts/lib/live-skip.ts +33 -0
  133. package/scripts/lib/mutation-qualify.ts +109 -3
  134. package/scripts/lib/probe-acp-turn.ts +33 -12
  135. package/scripts/lib/step-outcome.sh +88 -0
  136. package/scripts/meta-bridge-doctor.sh +6 -8
  137. package/scripts/meta-facts.ts +60 -0
  138. package/scripts/mutants/acp-augment.json +106 -0
  139. package/scripts/mutants/acp-cortex.json +2 -2
  140. package/scripts/mutants/acp-overlay.json +17 -0
  141. package/scripts/mutants/acp-prompt-lifecycle.json +100 -0
  142. package/scripts/mutants/acp-stop-reason.json +80 -0
  143. package/scripts/mutants/acp-stream-hooks.json +158 -0
  144. package/scripts/mutants/bridge-boot-resume.json +45 -0
  145. package/scripts/mutants/meta-facts.json +50 -0
  146. package/scripts/mutants/meta-identity.json +36 -0
  147. package/scripts/mutants/mux-boundary.json +196 -0
  148. package/scripts/mutants/mux-fresh-call.json +185 -0
  149. package/scripts/mutants/mux-launcher-fence.json +123 -0
  150. package/scripts/mutants/mux-parent-artifact.json +39 -0
  151. package/scripts/mutants/mux-resume-call.json +148 -0
  152. package/scripts/mutants/probe-ordering.json +6 -1021
  153. package/scripts/mutants/release-gate.json +140 -0
  154. package/scripts/mutants/resume-args.json +76 -0
  155. package/scripts/mutants/resume-launch-identity.json +96 -0
  156. package/scripts/mutants/v2-surface.json +74 -23
  157. package/scripts/mutants/v2-visible-resume.json +215 -0
  158. package/scripts/new-session-id.ts +9 -4
  159. package/scripts/smoke-acp-bundled-mcp-live.ts +4 -3
  160. package/scripts/smoke-acp-carrier-augment-live.ts +2 -2
  161. package/scripts/smoke-acp-cortex-live.ts +8 -14
  162. package/scripts/smoke-acp-long-turn-live.ts +185 -0
  163. package/scripts/smoke-acp-mcp-live.ts +2 -2
  164. package/scripts/smoke-acp-memory-containment-live.ts +2 -2
  165. package/scripts/smoke-acp-ordering-probe-live.ts +2 -2
  166. package/scripts/smoke-acp-overlay-live.ts +2 -2
  167. package/scripts/smoke-acp-provider-live.ts +2 -2
  168. package/scripts/smoke-acp-raw-turn-live.ts +3 -3
  169. package/scripts/smoke-acp-session-reuse-live.ts +2 -2
  170. package/scripts/smoke-acp-skill-live.ts +2 -2
  171. package/scripts/smoke-acp-socket-citizen-live.ts +4 -3
  172. package/scripts/smoke-acp-v2-send-live.ts +4 -3
  173. package/scripts/smoke-agy-native-push-live.ts +10 -20
  174. package/scripts/smoke-claude-native-resume-live.sh +13 -3
  175. package/scripts/smoke-entwurf-chain-live.ts +352 -0
  176. package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -3
  177. package/scripts/smoke-meta-honesty.sh +1 -1
  178. package/scripts/smoke-meta-install-state.sh +4 -0
  179. package/scripts/smoke-mux-fresh-call-live.ts +365 -0
  180. package/scripts/smoke-mux-lifecycle-live.ts +1136 -0
  181. package/scripts/smoke-pi-attach.ts +1 -1
  182. package/scripts/smoke-user-scope-citizen.sh +1 -1
  183. package/scripts/tsconfig.json +1 -0
  184. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-preflight.js +0 -160
  185. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +0 -273
  186. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn.js +0 -216
  187. package/pi-extensions/lib/entwurf-v2-spawn-production.ts +0 -373
  188. package/pi-extensions/lib/entwurf-v2-spawn.ts +0 -323
  189. package/scripts/check-acp-sdk-surface.ts +0 -236
  190. package/scripts/check-entwurf-v2-spawn-production.ts +0 -551
  191. package/scripts/check-entwurf-v2-spawn.ts +0 -399
  192. package/scripts/smoke-entwurf-v2-spawn-live.ts +0 -188
  193. package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +0 -469
package/VERIFY.md CHANGED
@@ -1,10 +1,17 @@
1
1
  # VERIFY.md
2
2
 
3
- Agent-driven verification guide for the `entwurf` surface as it stands in the working tree — the last **released** line is 0.12.x, and the tree is the **prepared 0.13.0 cut** (its tag, GitHub release, and publication are separate authorizations that have not run). The cut carries more than one change (the probe/ordering lane sits in it too); the change relevant to *this guide* is the second ACP backend. Rows below marked 0.12 are the released baseline; where 0.13.0 differs, it says so.
3
+ Agent-driven verification guide for the current `entwurf` surface. Machine-checkable
4
+ invariants live in gates; this file defines evidence strength, release acceptance,
5
+ and the manual judgements a gate cannot make.
4
6
 
5
- > **Current surface.** The bundled MCP server, `entwurf-bridge`, exposes five tools: `entwurf_v2`, `entwurf_peers`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native` (an explicit/manual fallback for binding an already-running native conversation). The ACP backends are **Claude** (the reference, 0.12) and, as of **0.13.0**, **Snowflake Cortex Code** (`cortex-` prefixed ids; deterministic axis `check-acp-cortex` in `pnpm check`, LIVE axis `smoke-acp-cortex-live` on demand — see [docs/acp-backend-rail.md](./docs/acp-backend-rail.md) §11-8 for the measured contract and its limits). Antigravity (`agy`) is a separate shipped **native-push citizen** lane, not an ACP backend: automatic `PreInvocation` birth + sender identity + live probe/direct injection. Codex is pi-native by default and has native delivery probe evidence; Gemini is a non-goal/historical ACP probe on 0.12. The 0.4.x `session-bridge` adapter, the 0.11.0 fat-bridge (`acp-bridge.ts` / `ensureBridgeSession`), and the v1 `entwurf` / `entwurf_resume` / `entwurf_send` verbs are **retired** — rows mentioning them survive in CHANGELOG/git as historical baseline, never as a runnable recipe.
7
+ > **Current surface.** `entwurf-bridge` exposes `entwurf_v2`, `entwurf_peers`,
8
+ > `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_self`, `entwurf_inbox_read`, and `entwurf_register_native`. The ACP
9
+ > backends are Claude and Snowflake Cortex Code. Antigravity is a separate shipped
10
+ > native-push citizen lane; Codex has delivery-probe evidence but no managed citizen
11
+ > lane. Retired v1 verbs and bridge implementations belong only in CHANGELOG/git.
6
12
 
7
- This is a **working document, not a metrics document**. The deterministic and live gates carry the machine-checkable invariants; this file carries only what a gate cannot judge — the human/agent reading of *whether the bridge is honestly itself*. Where a former manual procedure is now a gate, it is named as a pointer rather than re-spelled as a runnable script.
13
+ This is a working protocol, not a metrics ledger. Per-run counts, digests, and release
14
+ chronology belong in [BASELINE.md](./BASELINE.md), CHANGELOG, and release artifacts.
8
15
 
9
16
  VERIFY.md is the **agent-driven** surface; [BASELINE.md](./BASELINE.md) is the operator-driven one. One ACP-bridged model runs the checks against another and writes down what it sees — if the bridge is faithful, two replicants looking at the same mirror describe the mirror the same way. This is in-bridge cross-validation, not external evidence: verifier and subject share the same bridge, MCP servers, and overlay, so a uniform corruption of those would not surface here (that gap is what the L3+ rungs close).
10
17
 
@@ -33,84 +40,53 @@ Verification here is not a benchmark. In production we exchange short turns and
33
40
 
34
41
  ### The canonical floor — two entry points
35
42
 
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).
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**:
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.)
43
+ - **Deterministic floor — two tiers (#70):** `pnpm check` is the everyday CORE toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the FULL deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the frozen-candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT this document records meaning and principles, not the command list); a gate changes tier by semantic-class decision, never by getting faster or slower. Both tiers exclude the separately scheduled `check-gate-qualification`.
44
+ - **Discriminating power of that floor:** `./run.sh check-gate-qualification` (scheduled, not ambient: standalone when a lane changes a gate/mutant/matrix, in the CI `check` job on every push, and as a release-gate MUST step — no longer inside the default check chains) re-plants committed defect mutants (`scripts/mutants/*.json`, one per closed defect class) in an isolated snapshot repo and requires each to turn its gate red **bounded and at its claimed `[QK:<claim>]` signature** — a wrong-reason red fails, a baseline-red control voids the whole group, and the runner is negative-controlled on every run (zero-match/multi-match/survived/wrong-reason/hang/control-red/impurity). This measures whether the deterministic gates still *block* what they claim to block; it is **not a new evidence level** (L0–L5 are untouched) and never substitutes for LIVE evidence. Per-cut records cite claim IDs + killed mutant IDs — "N checks passed" alone is not evidence. `check-agy-permission-matrix` complements it with the enumerated permission contract space (literal cells + stated exclusion rules, oracle independent of the SUT).
45
+ - **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir> --cut` — `pnpm run check:full` + the v2-native live gates + the ACP plugin acceptance floor. It reports a **two-tier summary**:
46
+ - **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm run check:full`, `check-gate-qualification`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send), the axis wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-claude-native-resume-live`), and `smoke-entwurf-chain-live` — the cross-harness delivery chain (native Claude Code → pi GPT → pi ACP Sonnet → mailbox terminus) proving sender identity and replyability at every hop plus a real read receipt at the end. (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
40
47
  - **BEHAVIOR tier** (advisory, non-blocking): the resident-garden-guard positive (a model-in-loop `entwurf_self` turn). A BEHAVIOR FAIL is surfaced with its artifact path but **never blocks the cut**. The lane holds what the model *chooses*, never what our wiring fails to deliver — a gate that TELLS the model which tool to call stays MUST, because its failure is ours — measured 2026-07-24, when the tool turned out to be absent from the session schema in both observed failures (the bundled-MCP readiness gap recorded in `scripts/smoke-acp-v2-send-live.ts`).
41
- - LIVE-gated MUST steps honest-skip when `LIVE!=1`; a real cut needs `LIVE=1` with `SKIP=0`. A green MUST gate is **necessary, not sufficient** — GLG authorizes the cut.
48
+ - **Every MUST step is invoked and reports its own outcome.** Prerequisite-bearing LIVE MUST steps ride the P1 STEP OUTCOME protocol (`scripts/lib/step-outcome.sh`): exit 0 = PASS, exit 97 = SKIP (a prerequisite the step does not have, printed as an `[entwurf:skip]` line), anything else = FAIL. The two non-skippable static steps (`pnpm run check:full`, `check-gate-qualification`) are inline: 0 = PASS, nonzero = FAIL, no SKIP arm — they have no prerequisite to decline. A skip is never counted as a pass — that hole is what let a cortex-less host read as cortex acceptance. Without `--cut` this is the unattended diagnostic: SKIPs are reported and the run still exits 0. **`--cut` makes it acceptance and any MUST SKIP is red**, which is how "a real cut needs `LIVE=1` with `SKIP=0`" stopped being prose. A green MUST gate is **necessary, not sufficient** — GLG authorizes the cut.
42
49
  - **When cost-bearing MUST gates run (fixed 2026-07-23, the F6/F7 lesson):** a commit that touches a rail a MUST-tier live gate covers runs that gate **before cross-review is requested** — never parked behind "run it at approval time". Deferring a wired gate to a human decision is what let F6/F7 ship reviewed-and-approved; the wiring exists so the verdict never depends on who pressed enter. "배선이 없어 못 한 것은 OK, 배선이 있는데 안 돌린 것은 우리가 남긴 구멍이다." Model-in-loop cost is spent via the subscription-backed `entwurf` provider where the gate allows it, a free-tier native model otherwise; cost is a reason to pick the cheap target, not to skip the gate.
43
50
 
44
- > The aggregate release gate does not own a live agy conversation id, so agy's real native-push round trip is a separate acceptance axis: three fail-loud doctors plus `LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live`, followed by a fresh-conversation sender/reply check after package install. Its deterministic install/sender gates are already inside `pnpm check`; do not misreport the aggregate gate as live agy evidence.
51
+ > **Cortex is an on-demand axis, not an aggregate one.** Its rail needs an external Snowflake connection and login that the host owns, not the repo — so wiring it into the aggregate would block every cut taken on a host without that account. **The release aggregate does not re-certify Cortex**; `LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> ./run.sh smoke-acp-cortex-live` stays a required direct call whenever a cut changes Cortex rail code or an operator elects to certify that host. Its honest-skip behaviour is unchanged: run it without the connection and it reports protocol SKIP, never a pass.
45
52
  >
46
- > The authoritative per-cut counts live in BASELINE.md's HISTORY and CHANGELOG/git, not inline here (they drift against `run.sh`). Most recent recorded aggregate: **2026-07-24 (night) — MUST 16/1/0 + BEHAVIOR 1/0, EXIT=1** at `cbda097` — the single FAIL is the known bundled-MCP readiness race (ROADMAP 「🔴 OPEN」, observe-don't-fix; isolated re-runs pass). Most recent all-green floor: **2026-07-30 — MUST 17/0/0 + BEHAVIOR 1/0, EXIT=0** on the prepared 0.13.0 tree (parent landing HEAD `9f1c7dc`, scratch `/tmp/entwurf-release-gate-0.13.0.drnRyR`) the first aggregate completion carrying the cortex adapter and the probe lane; the step count did not move, because the cortex LIVE axis is deliberately outside this aggregate and is run on demand. Before it: **2026-07-24 — MUST 17/0/0 + BEHAVIOR 1/0, EXIT=0** at `7cbeb29b6afcfbaf4fc28da3b7929037c339113d` (the dependency-uplift HEAD: pi 0.82.0 + claude-agent-acp 0.61.0 / ACP SDK 1.3.0). The step count moved 16→17 with `smoke-acp-v2-send-live`; earlier that day it had moved 17→16 with the v2-cutover smoke retirements. A release cut requires the aggregate red to be resolved or explicitly ruled by GLG.
53
+ > A cut that touches the prompt-lifecycle contract (no wall clock on a running turn) owes one long-turn acceptance the aggregate floor is too short to carry: `LIVE=1 ./run.sh smoke-acp-long-turn-live` drives a real turn whose tool work outlasts the retired 600s cutoff and requires exactly one cold ACP bootstrap in the transcript. It takes >12 minutes by construction and is on-demand, not part of `release-gate`.
54
+ >
55
+ > **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-5.6-terra` and recorded-ACP `entwurf/claude-sonnet-5`, the only shape that re-injects a bridge extension), and the Claude Code cell ends where its capability ends: its resume is refused as `target-not-pi` with no window opened and no lock residue (the per-gid coordination lock is released).
56
+ >
57
+ > One cell cannot be fully fenced, and that is recorded rather than glossed: the recorded-ACP pi cell runs under the operator's REAL home, because its provider spawns `claude` as a child that authenticates from there — measured, a fenced HOME kills that turn with `Authentication required` before the model is ever reached, and `CLAUDE_CONFIG_DIR` alone does not fix it. That is the same trade `smoke-acp-bundled-mcp-live` already makes. While that cell runs, its citizen's control socket and per-gid lock exist under the operator's own `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks`; its meta store stays fixture, so no garden record is minted outside the fixture, and the run ends by proving all six real roots hold the entry sets they started with, with no fixture garden id and no leftover lock.
58
+ >
59
+ > Be honest about its cost, because it is a MUST: it spends real model turns on the operator's configured runtimes (two pi siblings, each resumed once, plus one Claude Code sibling), it READS the operator's real runtime config, and the siblings' native session transcripts stay in the real pi agent dir — they are not cleaned up, and they are part of the evidence a resume was real. The fence is per-axis rather than absolute: the four meta roots (records, mailbox, receivers, senders) are fixture for every cell, so no garden record is ever minted outside it; the native pi cell's control socket and v2 lock are fixture too; the ACP pi cell's are REAL and transient (see the paragraph above); and the Claude cell runs its runtime under the real HOME while its mailbox and meta stay fixture. The run ends by proving the operator's SIX real roots — the four meta roots plus `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks` — hold the entry sets they started with, with no fixture garden id anywhere, and that proof now runs on the failure path as well as the green one. Missing prerequisites decline with the protocol SKIP (97), which `release-gate --cut` refuses rather than rounding up.
60
+ >
61
+ > **Fresh-call LIVE is on-demand, not part of `release-gate`.** `LIVE=1 ./run.sh smoke-mux-fresh-call-live` opens configured Pi and Claude Code siblings, spends two model turns, and preserves their native transcripts; run it directly whenever a cut changes mux fresh-call/launch behavior. Its private tmux servers and fixture-bound entwurf write axes make it deterministic about garden-record/socket residue, but those real native turns should not appear unexpectedly in every aggregate cut.
62
+ >
63
+ > The aggregate release gate does not own a live agy conversation id, so agy's real native-push round trip is a separate acceptance axis: three fail-loud doctors plus `LIVE=1 AGY_CONVERSATION_ID=<id> ./run.sh smoke-agy-native-push-live`, followed by a fresh-conversation sender/reply check after package install. Its deterministic install/sender gates are already inside `pnpm run check:full`; do not misreport the aggregate gate as live agy evidence.
64
+ >
65
+ > Authoritative per-cut counts and digests live in BASELINE/CHANGELOG, not inline
66
+ > here; embedding them in the protocol makes a correct guide stale after every cut.
47
67
 
48
- ### Artifact / host certification matrix — #51 repair line → 0.12.8 stable
68
+ ### Release acceptance axes
49
69
 
50
- Do not collapse package evidence, fixture evidence, and a certified native host into
51
- one word such as “green.” They answer different questions.
70
+ Do not collapse source, package, fixture, and native-host evidence into one “green.”
52
71
 
53
- | Axis | Current evidence | Level / limit | Release reading |
54
- |---|---|---|---|
55
- | Source checkout | `pnpm check` on Node 24 Linux | Deterministic source floor; not an installed artifact | Necessary; cannot certify a consumer install. |
56
- | Project-local tarball | `check-pack-install` | Real `.tgz`, but checkout-visible, operator-owned, project-local | Installed-shape evidence; still maintainer-shaped. |
57
- | Linux artifact consumer | `check-install-container` in the required `artifact-consumer` CI job | **L3 package evidence:** one read-only candidate `.tgz`; checkout/repo `node_modules` invisible; non-root `npm install -g`; PATH shims; frozen package root; regular-file path+sha256 fence; canonical artifact path+sha256 and Node 24 image identity printed. Default CI packs once; `ENTWURF_CANDIDATE_TGZ` consumes a preserved caller artifact without re-pack. | Certifies the Linux package-consumer shape. Its fake Claude, planted plugin cache, stand-in owner, and `/proc` bridge are explicitly **fixtures**: they do not prove Claude installed the cache or that a real native Claude session woke. |
58
- | Direct Claude negative (B) | Claude Code 2.1.138 actual session | **L4 direct-native**, one NixOS host: fixture loaded (shell canary), `args` dropped, hook reported `exit_code: 0, outcome: success` | Justifies entwurf-side fail-loud and no old-version fallback. It did not run the final production argv shape. |
59
- | Direct Claude positive (B2) | Claude Code 2.1.217 actual session | **L4 direct-native**, one NixOS host: per-element args, literal `${HOME}`, direct parent join, FileChanged exit 2 idle wake | Justifies the proven floor and exec-form contract. It is not a second-OS acceptance run. |
60
- | Linux installed host | `doctor-meta-bridge` after package install, a **new** Claude session, and a live MCP child | **L3 host corroboration:** installed artifact + live `/proc` owner join | Published `0.12.8-repair.1` passed on maintainer + secondary Linux hosts on 2026-07-25 (BASELINE HISTORY). Missing live evidence is still `NOT CERTIFIED`; stable `0.12.8` earns its own package/CI/LIVE evidence. |
61
- | macOS Claude meta-bridge | New install is refused: strict live-owner certification cannot yet discover the MCP process without `/proc` | **Not yet verified/certified for this repair cut**; doctor nonzero | Linux is the only current certified axis. Darwin uninstall remains the honest inverse for older installs; the neutral package has no `os` restriction. This is not a permanent impossibility claim—future native validation may reopen macOS. |
62
- | WSL2 / Windows | No release lane | Unverified | Not supported by this cut. |
63
-
64
- The artifact-consumer run prints both the tarball sha256 and container image
65
- identity. Preserve those in the cut record. A synthetic doctor PASS proves the
66
- oracle can recognize a fully supplied fixture; only the installed doctor against a
67
- new native session proves that a real host supplied those layers.
68
-
69
- ### Stable 0.12.8 order (current execution; authority is mode-specific)
70
-
71
- The repo-local `entwurf-release` skill is a checkpointed state machine. Each mode
72
- is a separate authorization; one mode never implies the next. The repair history
73
- remains in CHANGELOG: repair.0 was field-broken, repair.1 restored delivery, and
74
- on 2026-07-25 its installed artifact passed the real native doctor on maintainer
75
- and secondary Linux hosts. That closed the explicit prerequisite for promoting
76
- this line to stable `0.12.8`; it does not transfer CI/LIVE/candidate evidence to
77
- the new stable bytes.
78
-
79
- 1. `land 0.12.8` pushes only the clean **pre-version landing HEAD** and requires
80
- a push-triggered `ci.yml` run whose `headSha` is exactly that commit. Current
81
- accepted landing: `1345688001ed6629bd0f58996a36134e7b7874bc`, run
82
- [30150824225](https://github.com/junghan0611/entwurf/actions/runs/30150824225),
83
- with `check`, `install-surface`, and `artifact-consumer` all success.
84
- 2. `prepare 0.12.8` promotes the changelog, sets the package version, reruns the
85
- deterministic and LIVE gates, and creates the release-prep commit. It never
86
- pushes, tags, creates a candidate, or publishes.
87
- 3. `make 0.12.8` pushes that clean prepared HEAD and requires the same three jobs
88
- on that exact version commit. Only after the second exact-SHA CI is green does
89
- it preserve and accept one candidate without repacking:
90
-
91
- ```bash
92
- ARTIFACT_DIR=$(mktemp -d /tmp/entwurf-release-candidate-0.12.8.XXXXXX)
93
- bash scripts/with-dist-lock.sh npm pack --dry-run=false --pack-destination "$ARTIFACT_DIR"
94
- CANDIDATE="$(realpath "$ARTIFACT_DIR/junghanacs-entwurf-0.12.8.tgz")"
95
- sha256sum "$CANDIDATE"
96
- ENTWURF_REQUIRE_DOCKER=1 ENTWURF_CANDIDATE_TGZ="$CANDIDATE" \
97
- ./run.sh check-install-container | tee "$ARTIFACT_DIR/acceptance.log"
98
- ```
99
-
100
- The gate must print caller-preserved candidate mode, the same canonical path
101
- and SHA-256, and the image identity. `make` then tags the exact prepared SHA
102
- and creates the GitHub release. Never repack accepted bytes.
103
- 4. Only an explicit `publish 0.12.8 <absolute-candidate> latest` may publish the
104
- accepted file. Registry proof requires `latest=0.12.8` while preserving
105
- `repair=0.12.8-repair.1`, followed by the registry-installed smoke.
106
-
107
- Invoking `land`, `prepare`, `make`, or `publish` grants only that named mode's
108
- authority. `prepare` stops at a local commit; `make` and `publish` remain separate
109
- GLG decisions.
72
+ | Axis | Required proof | Limit |
73
+ |---|---|---|
74
+ | Source | `pnpm run check:full` + `./run.sh check-gate-qualification` | Does not prove an installed consumer. |
75
+ | Packed install | `check-pack-install` | Real tarball, but checkout-visible. |
76
+ | Linux artifact consumer | required `check-install-container` CI job against one preserved candidate | Fixtures prove package/oracle shape, not a real Claude lifecycle. |
77
+ | Exact release commit | all required CI jobs green at the exact SHA | A different green SHA is not transferable evidence. |
78
+ | LIVE runtime | `LIVE=1 ./run.sh release-gate <scratch> --cut` plus any shipped on-demand backend axis | `--cut` enforces `SKIP=0`; a red wired gate blocks the cut. |
79
+ | Native Claude host | installed strict doctor against a new real session | Missing live join is `NOT CERTIFIED`, not a fixture PASS. |
80
+ | Native agy host | three doctors plus conversation-id-gated native-push round trip | Aggregate release-gate does not own an agy conversation id. |
81
+
82
+ The repo-local `entwurf-release` skill owns the `land → prepare → make → publish`
83
+ state machine. Each mode is a separate GLG authorization. Preserve one candidate,
84
+ accept and publish those exact bytes without repacking, and record its digest and
85
+ consumer image outside this standing protocol.
110
86
 
111
87
  ### Verifying the two capabilities a gate cannot fully judge
112
88
 
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.
89
+ - **Garden-id delivery:** discover a target with `entwurf_peers`, then `entwurf_v2 fire-and-forget` the intent axis is single-valued since the visible-first cut. It reaches a live pi target over its control socket, a deliverable self-fetch citizen through the mailbox, and a probe-alive native-push conversation by direct injection. A DORMANT in-domain citizen rejects as `dormant-fire-forget-unsupported` delivery never wakes it; reopen it with the separate lifecycle verb `entwurf_resume_call {target}`, then dispatch again. A wrong target state is rejected, never auto-fixed and never launched into.
114
90
  - **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.
115
91
  - **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.
116
92
 
@@ -136,7 +112,7 @@ When injecting a fact for a continuity check, use **plaintext that does not trig
136
112
 
137
113
  ### bridge continuity vs semantic continuity
138
114
 
139
- - **bridge continuity:** same `sessionKey` / same `acpSessionId` via in-memory reuse or persisted resume/load (bootstrap `path=reuse|resume|load`).
115
+ - **bridge continuity:** same `sessionKey` / same `acpSessionId` through in-memory process-scoped reuse. Persisted session records are written for a future resume/load lane but are not consumed today.
140
116
  - **semantic continuity:** a fact from a prior turn is retrievable in a later turn.
141
117
 
142
118
  Either can be alive while the other looks dead (the wording case above is bridge-alive / semantic-looks-dead). When in doubt, change the wording and retry once, and check the `[entwurf:bootstrap]` lines in bridge stderr. No automated smoke separates these yet.
@@ -145,7 +121,7 @@ Either can be alive while the other looks dead (the wording case above is bridge
145
121
 
146
122
  The goal is not merely "invoke Claude Code." We want:
147
123
 
148
- 1. **Session continuity at the agent-shell level** — through ACP session resume/load/new, not re-throwing a text blob.
124
+ 1. **Session continuity at the agent-shell level** — process-scoped turns reuse one live ACP session; fresh/turn-scoped paths open a new one rather than reconstructing a transcript inside entwurf.
149
125
  2. **Preservation of pi harness semantics** — pi session files / transcripts / memory pipeline stay a shared axis.
150
126
  3. **restart-hygienic** — process-scoped reuse continues the same ACP session across turns inside a long-lived resident; persisted records are written/validated for the future resume-load lane, not the live continuity path today.
151
127
  4. **Thin bridge** — no second harness built inside this repo.
@@ -185,7 +161,7 @@ cd "$REPO_DIR" && ./run.sh setup "$PROJECT_DIR"
185
161
  ### 1.2 Live acceptance (optional)
186
162
 
187
163
  ```bash
188
- LIVE=1 ./run.sh release-gate /path/to/consumer-project
164
+ LIVE=1 ./run.sh release-gate /path/to/consumer-project --cut
189
165
  pi --provider entwurf --model claude-sonnet-5 -p "reply with ok only" # one-turn smoke
190
166
  ```
191
167
 
@@ -197,13 +173,18 @@ addressable sends require `--entwurf-control` (measured 2026-07-24: the same
197
173
  one-shot with that flag returns its own gid and delivers `entwurf_v2` to a peer
198
174
  mailbox with `origin=pi-session`, `replyable=true`).
199
175
 
200
- `setup` runs `pnpm install` + project/user-scope install + detected native-harness wiring (Claude and/or agy) + the v2 install smoke. A green setup proves the required core path and reports optional-harness degradation; it does **not** replace the native-harness doctors. The full aggregate live floor is still `LIVE=1 ./run.sh release-gate`, with agy's conversation-id-gated round trip verified separately.
176
+ `setup` runs `pnpm install` + project/user-scope install + detected native-harness wiring (Claude and/or agy) + the v2 install smoke. A green setup proves the required core path and reports optional-harness degradation; it does **not** replace the native-harness doctors. The full aggregate live floor is still `LIVE=1 ./run.sh release-gate <scratch> --cut` — without `--cut` it is a diagnostic pass, not acceptance — with agy's conversation-id-gated round trip verified separately.
201
177
 
202
178
  ### 1.4 Cross-install / cross-backend parity (optional, high-value)
203
179
 
204
- Compare a fresh self-awareness report across axes: (1) same backend, different install path — answer must be path-invariant; (2) same backend, different machine — identical native tool list + MCP server/tool set; (3) different backend, same bridge — same garden capability but **different** native tool surface (a Claude session reporting another backend's native tools is a fail); (4) native pi routing vs ACP-bridged, same model — the native target reports no `entwurf-bridge` MCP (capability via pi's extension surface), while the ACP target reports it as the single MCP server. Honest "native: I cannot tell" hedging is PASS on the native side. Claude axes 1–4 are closed. agy is graded by the separate native-citizen checklist above, not by pretending it has Claude's ACP overlay. Gemini remains probe-only on 0.12.
180
+ Compare a fresh self-awareness report across axes: (1) same backend, different install path — answer must be path-invariant; (2) same backend, different machine — identical native tool list + MCP server/tool set; (3) different backend, same bridge — same garden capability but **different** native tool surface (a Claude session reporting another backend's native tools is a fail); (4) native pi routing vs ACP-bridged, same model — the native target reports no `entwurf-bridge` MCP (capability via pi's extension surface), while the ACP target reports it as the single MCP server. Honest "native: I cannot tell" hedging is PASS on the native side. agy is graded by its native-citizen checklist, not by pretending it has an ACP overlay.
205
181
 
206
- **Cortex (0.13.0) on axis 3.** Cortex is the first real *different backend, same bridge* subject, and it is the sharpest form of this axis: a cortex session must report the garden capability (`entwurf-bridge` reachable, record-backed peers) while its native tool surface is cortex's own, never Claude's — a cortex session listing Claude's built-ins is a fail. Two contract facts to grade against rather than re-derive: the callable identifier shape is the same `mcp__<server>__<tool>` convention as Claude (**measured**, §11-8), and cortex is **system-prompt-carrier-less**, so the operator engraving arrives at the head of the first-user augment instead of in a system prompt — a cortex session claiming a system-prompt engraving is reporting something it does not have. Axis 1 (install-path invariance) is split as of 0.13.0: the **deterministic** half is closed — `check-pack-install` enumerates the exact six curated rows out of the installed package's own model list — while the **live** half is a release-blocking `make` tag gate (the preserved exact candidate installed into a fresh temporary root driving one cold `entwurf/cortex-claude-sonnet-5` turn from those installed bytes). Until that gate runs, installed-artifact evidence and real-Cortex evidence have never met in one execution. Axis 2 (second machine) is unrun.
182
+ **Cortex on axis 3.** A cortex session must expose the same garden capability
183
+ while keeping cortex's own native tool surface. Its callable MCP identifier shape is
184
+ the same as Claude's, but it has no system-prompt carrier: engraving is prepended to
185
+ the first user augment. Installed-model enumeration is deterministic; candidate-installed
186
+ LIVE Cortex acceptance and its remaining host limits are recorded per cut rather than
187
+ frozen here.
207
188
 
208
189
  ---
209
190
 
@@ -226,7 +207,7 @@ Pass (carrier honesty): the subject distinguishes engraving from pi-context-augm
226
207
 
227
208
  - **Layer 0 — self-awareness:** ask environment self-awareness / MCP visibility / upstream-instruction awareness, guessing prohibited. Pass: recognizes native tool family, says "I don't know" honestly, answers MCP visibility only as configured, describes upstream instruction type without reproducing internal prompts. Fail: claims a nonexistent tool, conflates pi-custom and native tools, hallucinates MCP visibility, or conflates the two carriers (§1A.0).
228
209
  - **Layer 1 — native tool use:** throw file-reading / structure-analysis / regression-hunting tasks. Pass: Read/Edit/Bash/Grep/Glob selection is natural; no detour through MCP or recursive `pi`. Fail: strange detours for simple reads; speaks from memory without reading.
229
- - **Layer 2 — MCP boundary:** by default the five entwurf MCP tools are not visible (they appear only when `entwurf-bridge` is registered). Pass: says invisible tools are not visible; explains the native-vs-MCP boundary; treats `entwurf_register_native` as binding an already-running conversation, never as fresh spawn. Fail: pretends to use an unseen tool; mimics entwurf via recursive `pi`.
210
+ - **Layer 2 — MCP boundary:** by default the seven entwurf MCP tools are not visible (they appear only when `entwurf-bridge` is registered). Pass: says invisible tools are not visible; explains the native-vs-MCP boundary; treats `entwurf_register_native` as binding an already-running conversation, never as fresh spawn. Fail: pretends to use an unseen tool; mimics entwurf via recursive `pi`.
230
211
  - **Layer 3 — focus across turns:** inject a fact, then accumulate turns mixing retrieval/exploration. Pass (post-0.4.1): after **8 turns** holds **3+ early facts** incl. **one verbatim string injected before turn 5**; no repeated exploration, no self-contradiction, no tool-strategy drift. Fail: forgets early reads; paraphrases instead of returning the verbatim string. Note: entwurf exposes no user-facing compaction; use the backend's `usage_update` footer as an overflow-risk signal (it follows the ACP backend's `used/size`, not pi's visible-transcript estimate).
231
212
  - **Layer 4 — vs direct Claude Code:** requires a verifier holding **both** the `entwurf` and a direct path (human-in-loop, or both transport handles). Compare latency / native tool accuracy / detours / boundary confusion / quality around turns 10–15. Repeated tool confusion, long-turn forgetting, or boundary workarounds are a fail.
232
213
 
@@ -243,8 +224,9 @@ The single-turn / multi-turn / cross-process / persistence-boundary / shutdown i
243
224
  | Single-turn prompt extraction, SessionStart hook not mistaken for prompt | `smoke-acp-raw-turn-live`, `check-acp-prompt-builder` |
244
225
  | Multi-turn continuity + recall (process-scoped reuse) | `smoke-acp-session-reuse-live`, `check-acp-session-reuse` |
245
226
  | Cross-process continuity / cache before-after | `check-acp-session-store` (signature, decideBootstrap, persist/parse) |
246
- | Lifecycle policy — a turn-scoped `cwd:` fallback is never a persisted resume/load path; process-scoped records are hashed-`sessionKey` records | `check-acp-session-store` (`resolveLifecyclePolicy` turn-scoped→always-new, `decideBootstrap`, sha256 `SessionRecord` build/parse/roundtrip) — the former inline `acp-bridge.ts` repro is retired with the fat-bridge |
227
+ | Lifecycle policy — turn-scoped is always new; process-scoped may reuse only the live in-memory session; persisted records are not a resume/load path today | `check-acp-session-store`, `check-acp-session-reuse` |
247
228
  | Tool-call / event mapping | `check-acp-event-mapper`, `smoke-acp-provider-live` |
229
+ | Prompt lifecycle — no wall-clock cutoff on a running turn; abort ends it by ACP `session/cancel` with bounded cleanup; a child death is reported with exit status + stderr on new AND reuse turns; our prompt-phase error text is not classified transient by pi | `check-acp-prompt-lifecycle`, `check-probe-ordering` |
248
230
  | Operator mcpServers / skills reach the live session | `smoke-acp-mcp-live`, `smoke-acp-skill-live`, `check-acp-config` |
249
231
  | Overlay isolation + memory containment | `check-acp-overlay`, `smoke-acp-memory-containment-live`, `check-acp-tool-surface` |
250
232
 
@@ -252,18 +234,16 @@ The single-turn / multi-turn / cross-process / persistence-boundary / shutdown i
252
234
 
253
235
  The literal callable identifier differs per backend — probe by asking the agent to print it **verbatim** (do not ask "hyphen or underscore" — ambiguous between outer separator and inner server name):
254
236
 
255
- | Backend | Literal identifier | Outer sep | Inner server name |
256
- |---|---|---|---|
257
- | Claude | `mcp__entwurf-bridge__entwurf_v2` | `__` | `entwurf-bridge` (hyphen) |
258
- | Cortex *(0.13.0)* | `mcp__entwurf-bridge__entwurf_v2` | `__` | `entwurf-bridge` (hyphen) — same shape as Claude, **measured** (§11-8) |
259
- | Codex | `mcp__entwurf_bridge__.entwurf_v2` | `__` | `entwurf_bridge` (underscore) + **literal dot** |
260
- | Gemini *(probe)* | `mcp_entwurf-bridge_entwurf_v2` | `_` (single) | `entwurf-bridge`, no dot |
237
+ | Backend | Literal identifier | Boundary |
238
+ |---|---|---|
239
+ | Claude | `mcp__entwurf-bridge__entwurf_v2` | native Claude tool surface + explicit MCP server |
240
+ | Cortex | `mcp__entwurf-bridge__entwurf_v2` | same identifier shape, different native tool surface |
261
241
 
262
- A Claude session reporting the underscore form, or any cross-shape leak, is a backend-identification leak. Released 0.12 baseline is Claude; cortex joins it in 0.13.0 and is the one row whose shape had to be *measured* rather than assumed (identical to Claude's — so this row cannot discriminate Claude from Cortex, and the tool-surface axis in §1.4 is what does). The Codex/Gemini rows are reference for the probe lanes.
242
+ The identifier cannot distinguish Claude from Cortex; native tools and carrier facts must.
263
243
 
264
- ### 2.2 MCP injection visibility — equal across resume/load/new
244
+ ### 2.2 MCP injection visibility
265
245
 
266
- The sole MCP responsibility of `entwurf` is to inject `entwurfProvider.mcpServers` equally into `newSession` / `resumeSession` / `loadSession`. Ask "list the visible MCP server names": the registered `entwurf-bridge` appears, unregistered MCPs do not (no automatic `~/.mcp.json` loading); the list is identical every turn; changing `entwurfProvider.mcpServers` changes `bridgeConfigSignature` and forces a new session. `check-acp-config` + `smoke-acp-mcp-live` pin this; the manual check is an honesty corroboration.
246
+ The sole MCP responsibility of `entwurf` is to project explicit `entwurfProvider.mcpServers` into every newly opened backend session. Ask for visible MCP server names: `entwurf-bridge` appears, ambient servers do not, and changing the declaration changes `bridgeConfigSignature` so a live incompatible session is replaced rather than silently reused. `check-acp-config` and `smoke-acp-mcp-live` pin this; the manual check is honesty corroboration.
267
247
 
268
248
  ### 2.3 Process / cache hygiene — the orphan bound (§gate-external judgement)
269
249
 
@@ -274,7 +254,7 @@ AFTER_<BACKEND> ≤ BEFORE_<BACKEND> + (distinct alive
274
254
  (sessionKey, backend, modelId, bridgeConfigSignature) tuples this run holds open)
275
255
  ```
276
256
 
277
- An **upper bound**, not an equation: child reuse (one `entwurf` + N resumes share one child → delta 0 is expected) and idle reaping push `AFTER` below it; a config-signature or `(provider, model)` switch pushes it up by 1. `AFTER > BEFORE + alive_tuples` is the actionable signal — an unexpected child appeared. Walk the parent chain (`pgrep -af 'claude-agent-acp|codex-acp'` → `ps -o ppid=`); any ACP child whose parent `pi` has exited is an **orphan** flag and preserve as evidence.
257
+ An **upper bound**, not an equation: child reuse and idle reaping may keep the delta below it; a config-signature or `(provider, model)` switch may add one. `AFTER > BEFORE + alive_tuples` is actionable. Walk the backend process parent chain; any ACP child whose parent `pi` has exited is an orphan—preserve it as evidence.
278
258
 
279
259
  ### 2.4 pi session record as a shared memory axis
280
260
 
@@ -289,15 +269,15 @@ Pass: user/assistant turns accumulate normally; the transcript is not broken/emp
289
269
 
290
270
  ---
291
271
 
292
- ## 3. Pass criteria — the 0.12 release floor
272
+ ## 3. Pass criteria — current release floor
293
273
 
294
274
  The minimum passing bar:
295
275
 
296
- 1. **Deterministic floor green:** `pnpm check` passes (lint + typecheck + the `check-*` gate set + `check-pack`).
276
+ 1. **Deterministic floor green:** `pnpm run check:full` passes (the core tier plus the hermetic-integration and package/install tiers, incl. `check-pack`), plus a `./run.sh check-gate-qualification` green on the same candidate.
297
277
  2. **All three CI jobs green on the exact release commit:** `check`, `install-surface`, and the required Linux `artifact-consumer`; preserve the latter's tarball digest and image identity.
298
- 3. **Live floor MUST green:** `LIVE=1 ./run.sh release-gate <dir>` reports `MUST PASS=N FAIL=0 SKIP=0`; a BEHAVIOR FAIL is advisory, not blocking.
278
+ 3. **Live floor MUST green:** `LIVE=1 ./run.sh release-gate <dir> --cut` exits 0 reporting `MUST PASS=N FAIL=0 SKIP=0`; with `--cut` a single SKIP is red, so the exit code itself now carries this condition. A BEHAVIOR FAIL is advisory, not blocking.
299
279
  4. **Native-host doctor green where the Claude meta-bridge is claimed:** a new post-install Claude session exists, live evidence is present, and the installed `doctor-meta-bridge` exits 0. `NOT CERTIFIED` is a release failure for that host, not a skip.
300
- 5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge` as the single MCP server with its five current tools, and presents a backend-native (not normalized) tool surface.
280
+ 5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge` as the single MCP server with its seven current tools, and presents a backend-native (not normalized) tool surface.
301
281
  6. **Carrier separation honored:** engraving vs pi-context-augment kept distinct (§1A.0); no bridge-identity narrative attributed to the engraving carrier.
302
282
  7. **agy shipped lane accepted:** all three agy doctors are green; automatic birth/statusline/sender identity and same-gid native-push reply are confirmed in a fresh conversation. `agentId=meta-session/antigravity` is correct; model display is not part of that contract. Same-pid concurrent conversation invocation is not claimed.
303
283
  8. **Boundary preservation across backends/machines:** for every shipped or explicitly probed backend, regardless of install path or host, no cross-backend tool-surface contamination and no confabulation about pi internals.
@@ -313,9 +293,8 @@ Passing establishes a **release verification floor**, not an 8-hour/day operatio
313
293
 
314
294
  - **`ENTWURF_CHILD_STDERR_LOG`** mirrors child stderr to a file for bootstrap-path visibility — but it must be present at **bridge-process spawn time**; `export` from a shell already bound to a running bridge does not propagate. Restart the parent session with it exported, then `grep -E '\[entwurf:(bootstrap|model-switch|cancel|shutdown)\]' "$ENTWURF_CHILD_STDERR_LOG"`.
315
295
  - **Retired dedicated smokes, live code invariants** (manual/troubleshooting only — *not* part of the release floor):
316
- - *Model-switch lock* — entwurf sessions are locked to their starting model. Gate: `check-model-lock` (in `pnpm check`). The dedicated live `smoke-model-switch` was retired in v2; the invariant lives in `pi-extensions/model-lock.ts` (extension guard) + `session-store.ts` `SessionModelLockedError` (the `decideBootstrap` fail-loud model lock).
296
+ - *Model-switch lock* — entwurf sessions are locked to their starting model. Gate: `check-model-lock` (in `pnpm check`, core tier). The dedicated live `smoke-model-switch` was retired in v2; the invariant lives in `pi-extensions/model-lock.ts` (extension guard) + `session-store.ts` `SessionModelLockedError` (the `decideBootstrap` fail-loud model lock).
317
297
  - *Cancel / abort cleanup* — `onAbort` → `cancelActivePrompt()` (session stays reusable); the stream catch closes the bridge only on `stopReason === "error"`. Dedicated `smoke-cancel` retired; invariant in code.
318
- - *Transcript-poison invalidation (#12)* — **historical (0.11):** a poisoned backend transcript (empty text block ± `cache_control`) returned the same Anthropic 400 forever, handled by a dedicated classifier + `verify-transcript-poison` smoke. Both were retired in the 0.12 cutover; there is **no dedicated classifier or gate on the current surface** — recorded only so the failure mode is not forgotten.
319
298
 
320
299
  ### Evidence preservation when a problem occurs
321
300
 
package/demo/README.md CHANGED
@@ -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.1)
140
+ - `pi` on PATH (current floor 0.84.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)
@@ -76,12 +76,10 @@ tmux kill-session -t "$SESSION" 2>/dev/null || true
76
76
  # entwurf siblings can address it if a follow-up demo needs it.
77
77
  COMMON_ENV="ENTWURF_DEBUG=1 PI_EMACS_AGENT_SOCKET=$EMACS_SOCKET"
78
78
  COMMON_ARGS="--entwurf-control --emacs-agent-socket $EMACS_SOCKET"
79
- new_session_id() { bash "$REPO_ROOT/run.sh" new-session-id; }
80
79
 
81
80
  # ---------- start driver (single pane) ----------
82
- DRIVER_LAUNCH_ID=$(new_session_id)
83
81
  tmux new-session -d -s "$SESSION" -n demo -x 220 -y 50 \
84
- "$COMMON_ENV pi --session-id $DRIVER_LAUNCH_ID --model $DRIVER_MODEL $COMMON_ARGS 2>>$DRIVER_LOG"
82
+ "$COMMON_ENV pi --model $DRIVER_MODEL $COMMON_ARGS 2>>$DRIVER_LOG"
85
83
  DRIVER_PANE=$(tmux list-panes -s -t "$SESSION" -F '#{pane_id}' | head -1)
86
84
 
87
85
  # Give pi time to print its banner and reach the prompt.
package/demo/demo.sh CHANGED
@@ -77,7 +77,6 @@ tmux kill-session -t "$SESSION" 2>/dev/null || true
77
77
  # Plain `2>>` is POSIX sh — works under tmux's default /bin/sh.
78
78
  COMMON_ENV="ENTWURF_DEBUG=1 PI_EMACS_AGENT_SOCKET=$EMACS_SOCKET"
79
79
  COMMON_ARGS="--entwurf-control --emacs-agent-socket $EMACS_SOCKET"
80
- new_session_id() { bash "$REPO_ROOT/run.sh" new-session-id; }
81
80
 
82
81
  # Snapshot pre-existing control sockets so we can detect which one this demo's
83
82
  # peer pane creates. Without this, Scene 3 could greet an unrelated live pi
@@ -107,9 +106,8 @@ wait_for_new_socket() {
107
106
  # the operator's tmux `base-index` / `pane-base-index` settings.
108
107
 
109
108
  # ---------- start peer (top pane) — equivalent to: piat / piag / piat5 ----------
110
- PEER_LAUNCH_ID=$(new_session_id)
111
109
  tmux new-session -d -s "$SESSION" -n demo -x 220 -y 50 \
112
- "$COMMON_ENV pi --session-id $PEER_LAUNCH_ID --model $PEER_MODEL $COMMON_ARGS 2>>$PEER_LOG"
110
+ "$COMMON_ENV pi --model $PEER_MODEL $COMMON_ARGS 2>>$PEER_LOG"
113
111
  PEER_PANE=$(tmux list-panes -s -t "$SESSION" -F '#{pane_id}' | head -1)
114
112
 
115
113
  PEER_ID=$(wait_for_new_socket "$PRE_SOCKETS") || {
@@ -122,9 +120,8 @@ echo "Peer sessionId: $PEER_ID pane=$PEER_PANE"
122
120
  POST_PEER_SOCKETS=$(ls "$SOCK_DIR"/*.sock 2>/dev/null | sort || true)
123
121
 
124
122
  # ---------- start sender (bottom pane, split below) — equivalent to: pias / piao ----------
125
- SENDER_LAUNCH_ID=$(new_session_id)
126
123
  SENDER_PANE=$(tmux split-window -t "$PEER_PANE" -v -P -F '#{pane_id}' \
127
- "$COMMON_ENV pi --session-id $SENDER_LAUNCH_ID --model $SENDER_MODEL $COMMON_ARGS 2>>$SENDER_LOG")
124
+ "$COMMON_ENV pi --model $SENDER_MODEL $COMMON_ARGS 2>>$SENDER_LOG")
128
125
 
129
126
  SENDER_ID=$(wait_for_new_socket "$POST_PEER_SOCKETS") || {
130
127
  echo "ERROR: sender session never registered a control socket. Check $SENDER_LOG." >&2