@junghanacs/entwurf 0.13.0 → 0.13.1

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 (72) hide show
  1. package/AGENTS.md +5 -3
  2. package/BASELINE.md +57 -203
  3. package/CHANGELOG.md +19 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/DELIVERY.md +117 -261
  6. package/README.md +68 -408
  7. package/VERIFY.md +58 -87
  8. package/demo/README.md +1 -1
  9. package/docs/acp-backend-rail.md +231 -0
  10. package/docs/external-mcp-host.md +132 -0
  11. package/docs/fresh-cut-policy.md +99 -0
  12. package/docs/setup-clean-host.md +123 -328
  13. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +21 -48
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +12 -0
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +11 -10
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +1 -1
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +42 -1
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +4 -4
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +3 -3
  20. package/mcp/entwurf-bridge/src/index.ts +21 -48
  21. package/package.json +12 -9
  22. package/pi-extensions/entwurf-control.ts +20 -49
  23. package/pi-extensions/lib/acp/acp-client.ts +22 -0
  24. package/pi-extensions/lib/acp/augment.ts +42 -3
  25. package/pi-extensions/lib/acp/backend-adapter.ts +12 -11
  26. package/pi-extensions/lib/acp/backend.ts +305 -36
  27. package/pi-extensions/lib/acp/config.ts +1 -1
  28. package/pi-extensions/lib/acp/engraving.ts +43 -1
  29. package/pi-extensions/lib/acp/event-mapper.ts +16 -13
  30. package/pi-extensions/lib/acp/models.ts +4 -4
  31. package/pi-extensions/lib/acp/overlay.ts +3 -3
  32. package/prompts/engraving.md +13 -5
  33. package/run.sh +244 -108
  34. package/scripts/check-acp-carrier-augment.ts +246 -10
  35. package/scripts/check-acp-cortex.ts +5 -5
  36. package/scripts/check-acp-prompt-lifecycle.ts +565 -0
  37. package/scripts/check-acp-sdk-surface.ts +60 -21
  38. package/scripts/check-acp-stop-reason.ts +342 -0
  39. package/scripts/check-entwurf-v2-surface.ts +41 -0
  40. package/scripts/check-gate-qualification.ts +6 -3
  41. package/scripts/check-probe-ordering.ts +39 -7
  42. package/scripts/check-release-gate-outcomes.ts +332 -0
  43. package/scripts/lib/live-skip.ts +33 -0
  44. package/scripts/lib/probe-acp-turn.ts +33 -12
  45. package/scripts/lib/step-outcome.sh +88 -0
  46. package/scripts/mutants/acp-augment.json +106 -0
  47. package/scripts/mutants/acp-cortex.json +2 -2
  48. package/scripts/mutants/acp-prompt-lifecycle.json +100 -0
  49. package/scripts/mutants/acp-stop-reason.json +80 -0
  50. package/scripts/mutants/probe-ordering.json +27 -5
  51. package/scripts/mutants/release-gate.json +105 -0
  52. package/scripts/mutants/v2-surface.json +26 -15
  53. package/scripts/smoke-acp-bundled-mcp-live.ts +4 -3
  54. package/scripts/smoke-acp-carrier-augment-live.ts +2 -2
  55. package/scripts/smoke-acp-cortex-live.ts +8 -14
  56. package/scripts/smoke-acp-long-turn-live.ts +185 -0
  57. package/scripts/smoke-acp-mcp-live.ts +2 -2
  58. package/scripts/smoke-acp-memory-containment-live.ts +2 -2
  59. package/scripts/smoke-acp-ordering-probe-live.ts +2 -2
  60. package/scripts/smoke-acp-overlay-live.ts +2 -2
  61. package/scripts/smoke-acp-provider-live.ts +2 -2
  62. package/scripts/smoke-acp-raw-turn-live.ts +3 -3
  63. package/scripts/smoke-acp-session-reuse-live.ts +2 -2
  64. package/scripts/smoke-acp-skill-live.ts +2 -2
  65. package/scripts/smoke-acp-socket-citizen-live.ts +4 -3
  66. package/scripts/smoke-acp-v2-send-live.ts +4 -3
  67. package/scripts/smoke-agy-native-push-live.ts +4 -3
  68. package/scripts/smoke-claude-native-resume-live.sh +13 -3
  69. package/scripts/smoke-entwurf-chain-live.ts +352 -0
  70. package/scripts/smoke-entwurf-v2-matrix-live.ts +2 -2
  71. package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +2 -4
  72. package/scripts/smoke-meta-install-state.sh +4 -0
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_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
 
@@ -35,78 +42,39 @@ Verification here is not a benchmark. In production we exchange short turns and
35
42
 
36
43
  - **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
44
  - **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.)
45
+ - **Live floor:** `LIVE=1 ./run.sh release-gate <scratch-project-dir> --cut` — `pnpm check` + 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 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), 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 two axes wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-entwurf-v2-spawn-live`, `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** (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. 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
 
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 0.13.1 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.
52
+ >
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
+ >
44
55
  > 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.
45
56
  >
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.
57
+ > Authoritative per-cut counts and digests live in BASELINE/CHANGELOG, not inline
58
+ > here; embedding them in the protocol makes a correct guide stale after every cut.
47
59
 
48
- ### Artifact / host certification matrix — #51 repair line → 0.12.8 stable
60
+ ### Release acceptance axes
49
61
 
50
- Do not collapse package evidence, fixture evidence, and a certified native host into
51
- one word such as “green.” They answer different questions.
62
+ Do not collapse source, package, fixture, and native-host evidence into one “green.”
52
63
 
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.
64
+ | Axis | Required proof | Limit |
65
+ |---|---|---|
66
+ | Source | `pnpm check` | Does not prove an installed consumer. |
67
+ | Packed install | `check-pack-install` | Real tarball, but checkout-visible. |
68
+ | Linux artifact consumer | required `check-install-container` CI job against one preserved candidate | Fixtures prove package/oracle shape, not a real Claude lifecycle. |
69
+ | Exact release commit | all required CI jobs green at the exact SHA | A different green SHA is not transferable evidence. |
70
+ | 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. |
71
+ | Native Claude host | installed strict doctor against a new real session | Missing live join is `NOT CERTIFIED`, not a fixture PASS. |
72
+ | Native agy host | three doctors plus conversation-id-gated native-push round trip | Aggregate release-gate does not own an agy conversation id. |
73
+
74
+ The repo-local `entwurf-release` skill owns the `land → prepare → make → publish`
75
+ state machine. Each mode is a separate GLG authorization. Preserve one candidate,
76
+ accept and publish those exact bytes without repacking, and record its digest and
77
+ consumer image outside this standing protocol.
110
78
 
111
79
  ### Verifying the two capabilities a gate cannot fully judge
112
80
 
@@ -136,7 +104,7 @@ When injecting a fact for a continuity check, use **plaintext that does not trig
136
104
 
137
105
  ### bridge continuity vs semantic continuity
138
106
 
139
- - **bridge continuity:** same `sessionKey` / same `acpSessionId` via in-memory reuse or persisted resume/load (bootstrap `path=reuse|resume|load`).
107
+ - **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
108
  - **semantic continuity:** a fact from a prior turn is retrievable in a later turn.
141
109
 
142
110
  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 +113,7 @@ Either can be alive while the other looks dead (the wording case above is bridge
145
113
 
146
114
  The goal is not merely "invoke Claude Code." We want:
147
115
 
148
- 1. **Session continuity at the agent-shell level** — through ACP session resume/load/new, not re-throwing a text blob.
116
+ 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
117
  2. **Preservation of pi harness semantics** — pi session files / transcripts / memory pipeline stay a shared axis.
150
118
  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
119
  4. **Thin bridge** — no second harness built inside this repo.
@@ -185,7 +153,7 @@ cd "$REPO_DIR" && ./run.sh setup "$PROJECT_DIR"
185
153
  ### 1.2 Live acceptance (optional)
186
154
 
187
155
  ```bash
188
- LIVE=1 ./run.sh release-gate /path/to/consumer-project
156
+ LIVE=1 ./run.sh release-gate /path/to/consumer-project --cut
189
157
  pi --provider entwurf --model claude-sonnet-5 -p "reply with ok only" # one-turn smoke
190
158
  ```
191
159
 
@@ -197,13 +165,18 @@ addressable sends require `--entwurf-control` (measured 2026-07-24: the same
197
165
  one-shot with that flag returns its own gid and delivers `entwurf_v2` to a peer
198
166
  mailbox with `origin=pi-session`, `replyable=true`).
199
167
 
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.
168
+ `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
169
 
202
170
  ### 1.4 Cross-install / cross-backend parity (optional, high-value)
203
171
 
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.
172
+ 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
173
 
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.
174
+ **Cortex on axis 3.** A cortex session must expose the same garden capability
175
+ while keeping cortex's own native tool surface. Its callable MCP identifier shape is
176
+ the same as Claude's, but it has no system-prompt carrier: engraving is prepended to
177
+ the first user augment. Installed-model enumeration is deterministic; candidate-installed
178
+ LIVE Cortex acceptance and its remaining host limits are recorded per cut rather than
179
+ frozen here.
207
180
 
208
181
  ---
209
182
 
@@ -243,8 +216,9 @@ The single-turn / multi-turn / cross-process / persistence-boundary / shutdown i
243
216
  | Single-turn prompt extraction, SessionStart hook not mistaken for prompt | `smoke-acp-raw-turn-live`, `check-acp-prompt-builder` |
244
217
  | Multi-turn continuity + recall (process-scoped reuse) | `smoke-acp-session-reuse-live`, `check-acp-session-reuse` |
245
218
  | 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 |
219
+ | 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
220
  | Tool-call / event mapping | `check-acp-event-mapper`, `smoke-acp-provider-live` |
221
+ | 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
222
  | Operator mcpServers / skills reach the live session | `smoke-acp-mcp-live`, `smoke-acp-skill-live`, `check-acp-config` |
249
223
  | Overlay isolation + memory containment | `check-acp-overlay`, `smoke-acp-memory-containment-live`, `check-acp-tool-surface` |
250
224
 
@@ -252,18 +226,16 @@ The single-turn / multi-turn / cross-process / persistence-boundary / shutdown i
252
226
 
253
227
  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
228
 
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 |
229
+ | Backend | Literal identifier | Boundary |
230
+ |---|---|---|
231
+ | Claude | `mcp__entwurf-bridge__entwurf_v2` | native Claude tool surface + explicit MCP server |
232
+ | Cortex | `mcp__entwurf-bridge__entwurf_v2` | same identifier shape, different native tool surface |
261
233
 
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.
234
+ The identifier cannot distinguish Claude from Cortex; native tools and carrier facts must.
263
235
 
264
- ### 2.2 MCP injection visibility — equal across resume/load/new
236
+ ### 2.2 MCP injection visibility
265
237
 
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.
238
+ 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
239
 
268
240
  ### 2.3 Process / cache hygiene — the orphan bound (§gate-external judgement)
269
241
 
@@ -274,7 +246,7 @@ AFTER_<BACKEND> ≤ BEFORE_<BACKEND> + (distinct alive
274
246
  (sessionKey, backend, modelId, bridgeConfigSignature) tuples this run holds open)
275
247
  ```
276
248
 
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.
249
+ 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
250
 
279
251
  ### 2.4 pi session record as a shared memory axis
280
252
 
@@ -289,13 +261,13 @@ Pass: user/assistant turns accumulate normally; the transcript is not broken/emp
289
261
 
290
262
  ---
291
263
 
292
- ## 3. Pass criteria — the 0.12 release floor
264
+ ## 3. Pass criteria — current release floor
293
265
 
294
266
  The minimum passing bar:
295
267
 
296
268
  1. **Deterministic floor green:** `pnpm check` passes (lint + typecheck + the `check-*` gate set + `check-pack`).
297
269
  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.
270
+ 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
271
  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
272
  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.
301
273
  6. **Carrier separation honored:** engraving vs pi-context-augment kept distinct (§1A.0); no bridge-identity narrative attributed to the engraving carrier.
@@ -315,7 +287,6 @@ Passing establishes a **release verification floor**, not an 8-hour/day operatio
315
287
  - **Retired dedicated smokes, live code invariants** (manual/troubleshooting only — *not* part of the release floor):
316
288
  - *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).
317
289
  - *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
290
 
320
291
  ### Evidence preservation when a problem occurs
321
292
 
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.83.0)
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)
@@ -0,0 +1,231 @@
1
+ # ACP backend adapter rail
2
+
3
+ The ACP plugin is one provider with backend adapters behind a common turn loop.
4
+ It is not a second harness and does not create another citizen or socket layer. The
5
+ host pi session already owns the record-backed citizen identity; each backend owns
6
+ its own process, auth, transcript, and native tool surface.
7
+
8
+ Claude is the reference adapter. Snowflake Cortex Code is the second shipped adapter.
9
+ Implementation history and audit chronology live in CHANGELOG, issues, and git; this
10
+ document keeps the current contract and its open evidence boundary.
11
+
12
+ ## Boundary
13
+
14
+ | Layer | Owns |
15
+ |---|---|
16
+ | entwurf core | identity, facts, dispatch, rail choice, delivery evidence |
17
+ | ACP common loop | spawn, initialize, new session, model enforcement, prompt, event mapping, teardown |
18
+ | backend adapter | model routing, launch, overlay, carrier, backend settings, model enforcement details |
19
+ | backend runtime | credentials, subscription, transcript, native tools, native configuration semantics |
20
+
21
+ The common sequence is invariant:
22
+
23
+ ```text
24
+ resolve adapter once
25
+ → load backend settings and carrier
26
+ → materialize backend overlay
27
+ → spawn → initialize → newSession → enforceModel
28
+ → prompt → event map → retain-or-teardown
29
+ ```
30
+
31
+ No layer reconstructs a backend transcript, proxies credentials, scans ambient MCP
32
+ configuration, or grants tools through prose. Explicit `entwurfProvider.mcpServers`
33
+ and the callable schema are the tool truth.
34
+
35
+ ## Adapter contract
36
+
37
+ Source of truth: `pi-extensions/lib/acp/backend-adapter.ts`.
38
+
39
+ | Method | Responsibility |
40
+ |---|---|
41
+ | `routeModel` | Claim a curated id and return the backend-native id. Zero or multiple owners fail loud. |
42
+ | `curatedModels` | Contribute rows to the single `entwurf` provider. Non-Claude backends use a reserved prefix. |
43
+ | `resolveAdapterSettings` | Parse only this backend's settings into an opaque value. |
44
+ | `resolveLaunch` | Return command/argv; honor only the backend's explicit override. |
45
+ | `launchEnvDefaults` | Supply static launch environment defaults. |
46
+ | `ensureOverlay` | Materialize session isolation and return spawn environment overrides. |
47
+ | `loadCarrier` | Return a short operator carrier or `null` when the backend has no carrier. |
48
+ | `buildSessionMeta` | Build optional `newSession._meta` from the already-loaded carrier. |
49
+ | `enforceModel` | Make the requested native model authoritative before the prompt. |
50
+ | `configSignatureFields` | Return a stable primitive map whose changes invalidate reuse. |
51
+
52
+ `backend.ts` resolves the adapter once at turn entry. Common config never branches on
53
+ backend-specific keys; `adapterSettings` remains opaque until handed back to its owner.
54
+ A connection, model, carrier, MCP declaration, or overlay-relevant setting change must
55
+ change the reuse signature rather than mutate a live incompatible session.
56
+
57
+ A streaming message begins with `stopReason: "pending"`. ACP's terminal set is mapped
58
+ explicitly: `end_turn → stop`, `max_tokens → length`, `cancelled → aborted`; refusal,
59
+ exhausted turn budget, unknown, and absent reasons end as errors. The original ACP
60
+ reason is preserved in `rawStopReason`. Returning to a default-success branch is a
61
+ contract violation.
62
+
63
+ ### Prompt lifecycle — who may end a turn
64
+
65
+ Bootstrap (`initialize`, `newSession`, set-model) carries 30s wall-clock bounds: those
66
+ steps make no model progress, so a stuck one is a dead session. **The prompt carries
67
+ none.** A turn ends only on a lifecycle event:
68
+
69
+ | Ending | Behavior |
70
+ |---|---|
71
+ | the agent answers | mapped through the terminal set above |
72
+ | the operator aborts | ACP `session/cancel` first — the agent closes its own turn (`cancelled → aborted`); process-group teardown only after a bounded grace, so an abort always returns |
73
+ | the child dies / stdio ends | the turn fails naming the exit status and the session-scoped stderr tail, on both the new and the reuse path |
74
+
75
+ Elapsed time is not evidence of failure, and a silent turn is not a failed turn: tool
76
+ use, reasoning, and provider queueing all legitimately outrun any number we could pick.
77
+ Suspected stalls are handled by exposing progress, never by a killing timer.
78
+
79
+ A prompt-phase failure message is also part of the contract. pi classifies a failed
80
+ assistant message by matching its text against `RETRYABLE_PROVIDER_ERROR_PATTERN`
81
+ (`@earendil-works/pi-ai` `utils/retry`), and a "transient" verdict makes it replay the
82
+ WHOLE prompt from a cold session up to `retry.maxRetries` times. Our own prompt-phase
83
+ text must never read as transient — that pairing (absolute cutoff × blind retry) is what
84
+ turned one long turn into four in 0.13.0. Gates: `check-acp-prompt-lifecycle` (behavior,
85
+ with pi's own classifier as the oracle), `check-probe-ordering` (no production prompt
86
+ cutoff in source).
87
+
88
+ ## Shipped adapters
89
+
90
+ | Seam | Claude | Cortex Code |
91
+ |---|---|---|
92
+ | Model ids | unprefixed `claude-sonnet-5`, `claude-opus-5` | `cortex-auto`, `cortex-claude-opus-5`, `cortex-claude-sonnet-5`, `cortex-openai-gpt-5.4`; prefix stripped before set-model |
93
+ | Launch | bundled `claude-agent-acp`; `CLAUDE_AGENT_ACP_COMMAND` override | `cortex acp serve`; optional connection; `CORTEX_ACP_COMMAND` override; never a launch-time `-m` |
94
+ | Model authority | per-turn ACP set-model | per-turn ACP set-model; an unavailable curated id fails before prompt |
95
+ | Carrier | engraving in `_meta.systemPrompt` | no system-prompt carrier; engraving rides the first-user augment |
96
+ | Overlay | `CLAUDE_CONFIG_DIR` whitelist, configured-empty hooks, native memory hidden | session-scoped isolated HOME + `SNOWFLAKE_HOME`, private `cortex/mcp.json`, measured-minimum auth passthrough |
97
+ | MCP | explicit wire `mcpServers` | explicit declarations projected to private `mcp.json` because Cortex ignores the wire field |
98
+ | Backend setting | none | `cortexConnection`; env override wins and participates in the signature |
99
+
100
+ ### Claude
101
+
102
+ The bundled adapter resolves before any PATH fallback. Its overlay retains only the
103
+ auth/runtime state required by the Claude Agent SDK and hides operator memory, hooks,
104
+ agents, history, and local settings. Rich project/operator context rides the first-user
105
+ augment; the system carrier stays short to avoid changing billing semantics.
106
+
107
+ The carrier owns its own leading boundary. A string `_meta.systemPrompt` replaces the
108
+ `claude_code` preset, but the SDK still prefixes a fixed identity sentence and joins the
109
+ two with nothing, so the loader opens every rendered carrier with one blank line. The
110
+ template cannot supply it — the render is trimmed so operator whitespace never drifts the
111
+ reuse signature. That same rendered string is what `bridgeConfigSignature` folds and what
112
+ `buildSessionMeta` sends; normalizing it at either hop desynchronizes the wire from the
113
+ signature.
114
+
115
+ `clientCapabilities` intentionally remains empty. Terminal-output widgets and nested
116
+ subagent transcripts are therefore not requested. Enabling either is a separate
117
+ rendering contract, not a capability bit flip.
118
+
119
+ ### Cortex Code audit (D1–D10)
120
+
121
+ The original audit labels remain useful coordinates for source comments and gates:
122
+
123
+ | Audit | Landed contract |
124
+ |---|---|
125
+ | D1–D2 | Isolated HOME hides operator-global Claude/Cortex skills and settings; install-directory plugins remain a host fact. |
126
+ | D3 | Refuse `CORTEX_HOME` whenever present, including empty. |
127
+ | D4 | Author `autoUpdate: false`; launch only `cortex acp serve`. |
128
+ | D5–D6 | Pass through measured-minimum local auth; entwurf never runs or supplies authentication. |
129
+ | D7 | Four curated rows; enforce the stripped native id before prompt. |
130
+ | D8 | Credential boundary is AGENTS Hard Rule 9 and the ACP Plugin Boundary. |
131
+ | D9 | Project explicit MCP declarations into private `cortex/mcp.json`; wire `mcpServers` is ignored upstream. |
132
+ | D10 | Restore real operator HOME only for `entwurf-bridge`, so the isolated child still sees the garden store. |
133
+
134
+ Cortex containment was measured against the live CLI rather than copied from Claude:
135
+
136
+ - **Dual HOME:** the child receives an isolated `HOME` and `SNOWFLAKE_HOME`. Global
137
+ `~/.claude`/`~/.cortex` skills, hooks, settings, and operator `cortex/mcp.json` are
138
+ outside the session; explicit cwd project scope remains visible.
139
+ - **`CORTEX_HOME` presence refusal:** Cortex gives it precedence over
140
+ `SNOWFLAKE_HOME`; even an empty ambient value can make ownership ambiguous.
141
+ - **Auth passthrough:** only `connections.toml`, optional `config.toml`, and
142
+ `cortex/cache/credential_cache` are symlinked through. This narrows reachable paths;
143
+ it is not a read-only mount and entwurf never supplies the credential.
144
+ - **Launch integrity:** the overlay authors `autoUpdate: false`, preventing a CLI
145
+ replacement in the middle of a turn. The launch is exactly `cortex acp serve` plus
146
+ an optional connection; protocol initialization fails loud if a TUI was started.
147
+ - **MCP projection:** Cortex's ACP server ignores wire `mcpServers`, so the adapter
148
+ exact-writes an overlay-private `cortex/mcp.json`. Non-stdio declarations fail before
149
+ spawn. Only the `entwurf-bridge` entry receives the real operator HOME required to
150
+ see the garden store.
151
+ - **Carrier:** Cortex has no `_meta.systemPrompt` contract. The engraving is placed at
152
+ the head of the first-user augment; claiming a system-prompt engraving is false.
153
+
154
+ Cortex's bundled install-directory plugins are outside any HOME overlay and remain a
155
+ host fact. Also unclaimed: project-hook behavior on every host, the semantics of its
156
+ caller-session `_meta`, and cross-machine certification.
157
+
158
+ ## 11-7. Readiness boundary
159
+
160
+ A backend can return `newSession` before its declared MCP server is callable. This was
161
+ observed intermittently on the Claude rail and directly on Cortex's private `mcp.json`
162
+ path. Neither `claude-agent-acp` 0.64.0 nor the Cortex landing adds a client-side
163
+ readiness fence, and `mcpServerStatus()` is not called by the common loop.
164
+
165
+ ### 11-7-a/b. Instrument and first measurement
166
+
167
+ The ordering probe is an **instrument**, not a fix. It separates:
168
+
169
+ 1. client request/response ordering;
170
+ 2. backend MCP receive/reply markers;
171
+ 3. the first prompt/tool decision;
172
+ 4. probe admissibility (the test itself did not create the race).
173
+
174
+ Its first paired measurement was inconclusive. Do not convert that into “no race” or
175
+ “the adapter fixed it.” A green intermittent run measures one sample; a red run proves
176
+ the symptom remains.
177
+
178
+ ### 11-7-c. CLI snapshot producer
179
+
180
+ The B-name-snapshot producer is admissible only when the run pins the real target
181
+ executable and digest, refuses ambient overrides, preserves argv/stdin/stdout/stderr and
182
+ exit/signal behavior, bounds NDJSON framing, scrubs only the exact probe env allowlist,
183
+ and timestamps snapshot/prompt hand-offs inside the downstream write callback. One
184
+ post-wire init snapshot may support the controlled-absence row; malformed, duplicate,
185
+ pre-wire, unarmed, or target-mismatched snapshots invalidate the run rather than proving
186
+ absence. The deterministic mutants in `probe-ordering.json` are the detailed oracle.
187
+
188
+ Current probe contract and gates:
189
+
190
+ - `check-probe-ordering` — interval/envelope and marker ordering;
191
+ - `check-probe-cli-shim` — CLI shim admissibility and environment boundary;
192
+ - `smoke-acp-ordering-probe-live` — opt-in paired observation.
193
+
194
+ Until a causal fix lands, release gates continue to exercise real MCP availability and
195
+ fail when the callable surface is absent. Do not add sleeps or infer readiness from
196
+ `newSession` latency.
197
+
198
+ ## Verification
199
+
200
+ Deterministic floor:
201
+
202
+ ```bash
203
+ pnpm check
204
+ ./run.sh check-acp-provider-surface
205
+ ./run.sh check-acp-sdk-surface
206
+ ./run.sh check-acp-session-reuse
207
+ ./run.sh check-acp-stop-reason
208
+ ./run.sh check-acp-cortex
209
+ ./run.sh check-gate-qualification
210
+ ```
211
+
212
+ Live axes:
213
+
214
+ ```bash
215
+ LIVE=1 ./run.sh release-gate /path/to/scratch --cut
216
+ LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> \
217
+ ./run.sh smoke-acp-cortex-live
218
+ ```
219
+
220
+ The aggregate release gate is Claude-backed so a host without Cortex/Snowflake auth
221
+ can run the package floor. That means Cortex is **on demand**, not optional evidence:
222
+ a cut that changes or ships the Cortex rail must run and read its dedicated smoke.
223
+ Per-cut counts, digests, versions, and host observations belong in BASELINE/CHANGELOG,
224
+ not this standing contract.
225
+
226
+ ## Open work
227
+
228
+ - causal MCP-readiness diagnosis and, only with proof, a backend-invariant fence;
229
+ - broader installed-host and cross-machine Cortex evidence;
230
+ - Codex managed native-citizen work on the reserved 0.14.0 lane—separate from ACP;
231
+ - persisted ACP resume/load, which is not implemented by today's in-memory reuse.