@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.
- package/AGENTS.md +52 -17
- package/BASELINE.md +60 -206
- package/CHANGELOG.md +64 -0
- package/CONTRIBUTING.md +14 -10
- package/DELIVERY.md +118 -261
- package/README.md +91 -431
- package/VERIFY.md +74 -95
- package/demo/README.md +1 -1
- package/demo/demo-baseline.sh +1 -3
- package/demo/demo.sh +2 -5
- package/docs/acp-backend-rail.md +236 -0
- package/docs/external-mcp-host.md +131 -0
- package/docs/fresh-cut-policy.md +99 -0
- package/docs/setup-clean-host.md +124 -328
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +160 -67
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +12 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +11 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/engraving.js +42 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +4 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/overlay.js +11 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +7 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-core.js +13 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-resume-args.js +45 -40
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +117 -95
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-decider.js +23 -57
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +16 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-production.js +5 -53
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-release.js +21 -36
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-runner.js +3 -15
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send-fallback.js +12 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-send.js +2 -7
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +30 -67
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +256 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +91 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +258 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +202 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-placement.js +289 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +170 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +136 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/session-id.js +8 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/socket-discovery.js +3 -3
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +51 -0
- package/mcp/entwurf-bridge/dist/scripts/new-session-id.js +9 -4
- package/mcp/entwurf-bridge/src/index.ts +176 -67
- package/mcp/entwurf-bridge/start.sh +2 -2
- package/mcp/entwurf-bridge/test.sh +23 -9
- package/mcp/entwurf-bridge/tsconfig.build.json +11 -2
- package/package.json +25 -11
- package/pi-extensions/entwurf-control.ts +220 -71
- package/pi-extensions/lib/acp/acp-client.ts +22 -0
- package/pi-extensions/lib/acp/augment.ts +42 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +12 -11
- package/pi-extensions/lib/acp/backend.ts +366 -38
- package/pi-extensions/lib/acp/config.ts +1 -1
- package/pi-extensions/lib/acp/engraving.ts +43 -1
- package/pi-extensions/lib/acp/event-mapper.ts +16 -13
- package/pi-extensions/lib/acp/models.ts +4 -4
- package/pi-extensions/lib/acp/overlay.ts +11 -9
- package/pi-extensions/lib/entwurf-control-rpc.ts +7 -5
- package/pi-extensions/lib/entwurf-core.ts +15 -15
- package/pi-extensions/lib/entwurf-resume-args.ts +41 -52
- package/pi-extensions/lib/entwurf-v2-contract-schema.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-contract.ts +120 -99
- package/pi-extensions/lib/entwurf-v2-decider.ts +30 -91
- package/pi-extensions/lib/entwurf-v2-lock.ts +16 -7
- package/pi-extensions/lib/entwurf-v2-production.ts +4 -78
- package/pi-extensions/lib/entwurf-v2-release.ts +25 -49
- package/pi-extensions/lib/entwurf-v2-runner.ts +6 -21
- package/pi-extensions/lib/entwurf-v2-send-fallback.ts +12 -11
- package/pi-extensions/lib/entwurf-v2-send.ts +2 -7
- package/pi-extensions/lib/entwurf-v2-surface.ts +36 -76
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +370 -0
- package/pi-extensions/lib/meta-session.ts +93 -5
- package/pi-extensions/lib/mux-fresh-call.ts +328 -0
- package/pi-extensions/lib/mux-launch.ts +267 -0
- package/pi-extensions/lib/mux-placement.ts +387 -0
- package/pi-extensions/lib/mux-resume-call.ts +221 -0
- package/pi-extensions/lib/resume-launch-identity.ts +162 -0
- package/pi-extensions/lib/session-id.js +8 -5
- package/pi-extensions/lib/socket-discovery.ts +3 -3
- package/prompts/engraving.md +13 -5
- package/run.sh +688 -282
- package/scripts/agy-bridge-config.py +5 -1
- package/scripts/check-acp-backend-preflight.ts +1 -1
- package/scripts/check-acp-carrier-augment.ts +246 -10
- package/scripts/check-acp-cortex.ts +5 -5
- package/scripts/check-acp-overlay.ts +13 -3
- package/scripts/check-acp-prompt-lifecycle.ts +565 -0
- package/scripts/check-acp-stop-reason.ts +342 -0
- package/scripts/check-acp-stream-hooks.ts +504 -0
- package/scripts/check-elapsed.sh +25 -0
- package/scripts/check-entwurf-bridge-boot.ts +51 -4
- package/scripts/check-entwurf-bridge-pi-free.ts +6 -5
- package/scripts/check-entwurf-control-rpc.ts +4 -3
- package/scripts/check-entwurf-resume-args.ts +72 -70
- package/scripts/check-entwurf-session-identity.ts +14 -10
- package/scripts/check-entwurf-v2-contract.ts +34 -59
- package/scripts/check-entwurf-v2-decider.ts +17 -177
- package/scripts/check-entwurf-v2-lock.ts +5 -2
- package/scripts/check-entwurf-v2-matrix.ts +3 -53
- package/scripts/check-entwurf-v2-production.ts +2 -91
- package/scripts/check-entwurf-v2-release.ts +10 -105
- package/scripts/check-entwurf-v2-runner.ts +4 -85
- package/scripts/check-entwurf-v2-send-fallback.ts +5 -6
- package/scripts/check-entwurf-v2-send.ts +0 -28
- package/scripts/check-entwurf-v2-surface.ts +198 -128
- package/scripts/check-entwurf-v2-visible-resume.ts +445 -0
- package/scripts/check-fresh-cut-gate.sh +1 -1
- package/scripts/check-gate-qualification.ts +101 -7
- package/scripts/check-install-container.sh +10 -2
- package/scripts/check-install-surface.ts +1 -1
- package/scripts/check-keyset-overlap.py +1 -1
- package/scripts/check-meta-facts.ts +249 -0
- package/scripts/check-meta-identity-consumers.ts +1 -1
- package/scripts/check-meta-session.ts +169 -0
- package/scripts/check-mux-launch-tmux.ts +316 -0
- package/scripts/check-mux-launch.ts +288 -0
- package/scripts/check-mux-launcher-fence.ts +264 -0
- package/scripts/check-mux-parent-artifact.ts +195 -0
- package/scripts/check-mux-placement-tmux.ts +322 -0
- package/scripts/check-mux-placement.ts +323 -0
- package/scripts/check-mux-resume-call.ts +282 -0
- package/scripts/check-probe-cli-shim.ts +25 -22
- package/scripts/check-probe-ordering.ts +121 -81
- package/scripts/check-release-gate-outcomes.ts +452 -0
- package/scripts/check-resume-launch-identity.ts +244 -0
- package/scripts/check-socket-discovery.ts +1 -1
- package/scripts/fixtures/mux-parent-transcript.scrubbed.jsonl +3 -0
- package/scripts/inventory-verification-surface.ts +349 -0
- package/scripts/lib/claude-launcher-fence.ts +322 -0
- package/scripts/lib/live-skip.ts +33 -0
- package/scripts/lib/mutation-qualify.ts +109 -3
- package/scripts/lib/probe-acp-turn.ts +33 -12
- package/scripts/lib/step-outcome.sh +88 -0
- package/scripts/meta-bridge-doctor.sh +6 -8
- package/scripts/meta-facts.ts +60 -0
- package/scripts/mutants/acp-augment.json +106 -0
- package/scripts/mutants/acp-cortex.json +2 -2
- package/scripts/mutants/acp-overlay.json +17 -0
- package/scripts/mutants/acp-prompt-lifecycle.json +100 -0
- package/scripts/mutants/acp-stop-reason.json +80 -0
- package/scripts/mutants/acp-stream-hooks.json +158 -0
- package/scripts/mutants/bridge-boot-resume.json +45 -0
- package/scripts/mutants/meta-facts.json +50 -0
- package/scripts/mutants/meta-identity.json +36 -0
- package/scripts/mutants/mux-boundary.json +196 -0
- package/scripts/mutants/mux-fresh-call.json +185 -0
- package/scripts/mutants/mux-launcher-fence.json +123 -0
- package/scripts/mutants/mux-parent-artifact.json +39 -0
- package/scripts/mutants/mux-resume-call.json +148 -0
- package/scripts/mutants/probe-ordering.json +6 -1021
- package/scripts/mutants/release-gate.json +140 -0
- package/scripts/mutants/resume-args.json +76 -0
- package/scripts/mutants/resume-launch-identity.json +96 -0
- package/scripts/mutants/v2-surface.json +74 -23
- package/scripts/mutants/v2-visible-resume.json +215 -0
- package/scripts/new-session-id.ts +9 -4
- package/scripts/smoke-acp-bundled-mcp-live.ts +4 -3
- package/scripts/smoke-acp-carrier-augment-live.ts +2 -2
- package/scripts/smoke-acp-cortex-live.ts +8 -14
- package/scripts/smoke-acp-long-turn-live.ts +185 -0
- package/scripts/smoke-acp-mcp-live.ts +2 -2
- package/scripts/smoke-acp-memory-containment-live.ts +2 -2
- package/scripts/smoke-acp-ordering-probe-live.ts +2 -2
- package/scripts/smoke-acp-overlay-live.ts +2 -2
- package/scripts/smoke-acp-provider-live.ts +2 -2
- package/scripts/smoke-acp-raw-turn-live.ts +3 -3
- package/scripts/smoke-acp-session-reuse-live.ts +2 -2
- package/scripts/smoke-acp-skill-live.ts +2 -2
- package/scripts/smoke-acp-socket-citizen-live.ts +4 -3
- package/scripts/smoke-acp-v2-send-live.ts +4 -3
- package/scripts/smoke-agy-native-push-live.ts +10 -20
- package/scripts/smoke-claude-native-resume-live.sh +13 -3
- package/scripts/smoke-entwurf-chain-live.ts +352 -0
- package/scripts/smoke-entwurf-v2-matrix-live.ts +3 -3
- package/scripts/smoke-meta-honesty.sh +1 -1
- package/scripts/smoke-meta-install-state.sh +4 -0
- package/scripts/smoke-mux-fresh-call-live.ts +365 -0
- package/scripts/smoke-mux-lifecycle-live.ts +1136 -0
- package/scripts/smoke-pi-attach.ts +1 -1
- package/scripts/smoke-user-scope-citizen.sh +1 -1
- package/scripts/tsconfig.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-preflight.js +0 -160
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn-production.js +0 -273
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-spawn.js +0 -216
- package/pi-extensions/lib/entwurf-v2-spawn-production.ts +0 -373
- package/pi-extensions/lib/entwurf-v2-spawn.ts +0 -323
- package/scripts/check-acp-sdk-surface.ts +0 -236
- package/scripts/check-entwurf-v2-spawn-production.ts +0 -551
- package/scripts/check-entwurf-v2-spawn.ts +0 -399
- package/scripts/smoke-entwurf-v2-spawn-live.ts +0 -188
- package/scripts/smoke-entwurf-v2-spawn-resume-live.ts +0 -469
|
@@ -0,0 +1,236 @@
|
|
|
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.66.0 nor the Cortex landing adds a client-side
|
|
163
|
+
readiness fence, and `mcpServerStatus()` is not called by the common loop.
|
|
164
|
+
(Re-measured at the 0.65.0 → 0.66.0 bump: the goal extension is not a fence,
|
|
165
|
+
and `mcpServerStatus` appears nowhere in the 0.66.0 adapter source.)
|
|
166
|
+
|
|
167
|
+
### 11-7-a/b. Instrument and first measurement
|
|
168
|
+
|
|
169
|
+
The ordering probe is an **instrument**, not a fix. It separates:
|
|
170
|
+
|
|
171
|
+
1. client request/response ordering;
|
|
172
|
+
2. backend MCP receive/reply markers;
|
|
173
|
+
3. the first prompt/tool decision;
|
|
174
|
+
4. probe admissibility (the test itself did not create the race).
|
|
175
|
+
|
|
176
|
+
Its first paired measurement was inconclusive. Do not convert that into “no race” or
|
|
177
|
+
“the adapter fixed it.” A green intermittent run measures one sample; a red run proves
|
|
178
|
+
the symptom remains.
|
|
179
|
+
|
|
180
|
+
### 11-7-c. CLI snapshot producer
|
|
181
|
+
|
|
182
|
+
The B-name-snapshot producer is admissible only when the run pins the real target
|
|
183
|
+
executable and digest, refuses ambient overrides, preserves argv/stdin/stdout/stderr and
|
|
184
|
+
exit/signal behavior, bounds NDJSON framing, scrubs only the exact probe env allowlist,
|
|
185
|
+
and timestamps snapshot/prompt hand-offs inside the downstream write callback. One
|
|
186
|
+
post-wire init snapshot may support the controlled-absence row; malformed, duplicate,
|
|
187
|
+
pre-wire, unarmed, or target-mismatched snapshots invalidate the run rather than proving
|
|
188
|
+
absence. `check-probe-cli-shim` is the detailed producer oracle: its 20 direct
|
|
189
|
+
`[CHECK:*]` assertions remain, while their verification-infra replants were deliberately
|
|
190
|
+
removed by #70. `probe-ordering.json` retains only the product-subject no-production-prompt-cutoff
|
|
191
|
+
replant consumed by `check-probe-ordering`.
|
|
192
|
+
|
|
193
|
+
Current probe contract and gates:
|
|
194
|
+
|
|
195
|
+
- `check-probe-ordering` — interval/envelope and marker ordering;
|
|
196
|
+
- `check-probe-cli-shim` — CLI shim admissibility and environment boundary;
|
|
197
|
+
- `smoke-acp-ordering-probe-live` — opt-in paired observation.
|
|
198
|
+
|
|
199
|
+
Until a causal fix lands, release gates continue to exercise real MCP availability and
|
|
200
|
+
fail when the callable surface is absent. Do not add sleeps or infer readiness from
|
|
201
|
+
`newSession` latency.
|
|
202
|
+
|
|
203
|
+
## Verification
|
|
204
|
+
|
|
205
|
+
Deterministic floor:
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
pnpm run check:full
|
|
209
|
+
./run.sh check-acp-provider-surface
|
|
210
|
+
./run.sh check-acp-sdk-surface
|
|
211
|
+
./run.sh check-acp-session-reuse
|
|
212
|
+
./run.sh check-acp-stop-reason
|
|
213
|
+
./run.sh check-acp-cortex
|
|
214
|
+
./run.sh check-gate-qualification
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
Live axes:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
LIVE=1 ./run.sh release-gate /path/to/scratch --cut
|
|
221
|
+
LIVE=1 ENTWURF_ACP_CORTEX_CONNECTION=<conn> \
|
|
222
|
+
./run.sh smoke-acp-cortex-live
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
The aggregate release gate is Claude-backed so a host without Cortex/Snowflake auth
|
|
226
|
+
can run the package floor. That means Cortex is **on demand**, not optional evidence:
|
|
227
|
+
a cut that changes or ships the Cortex rail must run and read its dedicated smoke.
|
|
228
|
+
Per-cut counts, digests, versions, and host observations belong in BASELINE/CHANGELOG,
|
|
229
|
+
not this standing contract.
|
|
230
|
+
|
|
231
|
+
## Open work
|
|
232
|
+
|
|
233
|
+
- causal MCP-readiness diagnosis and, only with proof, a backend-invariant fence;
|
|
234
|
+
- broader installed-host and cross-machine Cortex evidence;
|
|
235
|
+
- any future Codex managed native-citizen lane—separate from ACP; 0.14.0 does not ship one;
|
|
236
|
+
- persisted ACP resume/load, which is not implemented by today's in-memory reuse.
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Wiring `entwurf-bridge` into an external MCP host
|
|
2
|
+
|
|
3
|
+
Per-harness registration for Claude Code, Codex CLI, and Antigravity, plus the
|
|
4
|
+
PATH/env boundary and the external vs garden-native semantics. `README.md` keeps only
|
|
5
|
+
the one-line registration; everything an operator needs to actually wire a host is here.
|
|
6
|
+
|
|
7
|
+
`entwurf-bridge` can also be registered in a separate MCP-aware harness (Claude Code, Codex CLI, Antigravity/`agy`, …). That host does **not** become a pi session and does **not** need to be ACP-backed. There are now two honest cases:
|
|
8
|
+
|
|
9
|
+
- **plain external MCP host**: no garden meta-record / sender marker. It can call the read surfaces (`entwurf_peers`, `entwurf_inbox_read`), but `entwurf_v2` sends are **refused by default** (#50 C4: "if we don't know who sent it, we don't send it"). The operator may wire the explicit hatch below; the send then goes out external/non-replyable.
|
|
10
|
+
- **garden-native native session**: a trusted lifecycle hook minted a garden id and sender marker — `SessionStart` for Claude Code, `PreInvocation` for agy. It is not a pi control-socket session, but it can be replyable by garden id when its own mailbox/probe rail says so.
|
|
11
|
+
|
|
12
|
+
**Which verb an external agent should reach for:** to deliver to / reply to a garden id, use **`entwurf_v2`** — it is the canonical delivery surface and the only one that reads whether the target is live pi, dormant pi, mailbox-backed Claude Code, or native-push Antigravity and routes correctly. Discover targets with `entwurf_peers`, confirm your own identity with `entwurf_self`, drain a mailbox with `entwurf_inbox_read`, and use `entwurf_register_native` only as the explicit/manual fallback for binding an already-running agy conversation (normal agy birth is automatic through the installed hook). Open a NEW sibling with **`entwurf_fresh_call`**, and reopen a DORMANT pi citizen under its own garden id with **`entwurf_resume_call {target}`**. Fresh call needs its selected runtime (`pi` or `claude`) on the server's PATH; resume call always needs `pi`. Both start a runtime, while delivery does not. (The old v1 verbs `entwurf` / `entwurf_resume` / `entwurf_send` are gone.)
|
|
13
|
+
|
|
14
|
+
Observed: Claude Code, Codex CLI, and Antigravity CLI all reach the read surfaces through this MCP bridge from a plain external host — `entwurf_peers` is a pure fact projection, while `entwurf_inbox_read` is a **mutating drain** (it archives the messages and stamps the read-receipt), so "read" here does not mean side-effect-free; **sending** needs an identity lane. Claude becomes symmetric/replyable through its mailbox-backed meta-session; agy becomes symmetric/replyable through its record-backed sender marker plus live native-push probe. Codex has no managed citizen lifecycle yet, so a Codex host cannot send without the explicit anonymous hatch below.
|
|
15
|
+
|
|
16
|
+
Prerequisites on the host running the external MCP client:
|
|
17
|
+
|
|
18
|
+
- A live pi session launched with `--entwurf-control` populates `~/.pi/entwurf-control/<gardenId>.sock` — the key is the **record's** garden id, never a transcript/session id (`PI_SESSION_ID` only carries the id record birth already established). Required for `entwurf_v2` control-socket dispatch and `entwurf_peers`.
|
|
19
|
+
|
|
20
|
+
> **PATH boundary.** MCP servers are often launched by GUI/editor daemons and may not inherit the interactive shell's PATH. No `entwurf_v2` rail launches a process, so this does not affect delivery — but `entwurf_fresh_call` and `entwurf_resume_call` do open a fixed runtime. If that runtime works in your terminal but an external-host call fails with `spawn pi ENOENT` or `spawn claude ENOENT`, pass a full PATH in the MCP server `env`, set `ENTWURF_BRIDGE_ENV_FILE` to a small shell file that exports PATH, or point the host at a wrapper that can find the runtime. `start.sh` sources only the explicit `ENTWURF_BRIDGE_ENV_FILE`; it never reads personal dotfiles automatically.
|
|
21
|
+
|
|
22
|
+
Example env file:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# ~/.config/entwurf-bridge/env.sh
|
|
26
|
+
export PATH="$HOME/.local/share/pnpm:$HOME/.local/bin:$HOME/.nvm/versions/node/v24.15.0/bin:$PATH"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then add it to the external MCP config:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"env": {
|
|
34
|
+
"ENTWURF_BRIDGE_ENV_FILE": "/home/operator/.config/entwurf-bridge/env.sh",
|
|
35
|
+
"ENTWURF_BRIDGE_EXTERNAL_AGENT_ID": "external-mcp/claude-code"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Anonymous sender hatch (explicit, documented — never a default).** The bridge refuses an `entwurf_v2` send when the process has neither pi-session env (`PI_SESSION_ID` + `PI_AGENT_ID`) nor a trusted meta-sender marker (#50 C4). A deliberately-anonymous external host — e.g. a Codex CLI wiring, which has no managed citizen lifecycle — may opt out by adding `"ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER": "1"` to the MCP server `env`. The cost is honest and fixed: the send lands with `origin: "external-mcp"`, `replyable: false` (there is no reply address), and `wants_reply: true` stays pointless. The retired opt-in `ENTWURF_BRIDGE_REQUIRE_META_SENDER` is no longer read — its demand became the default, so a stale copy in an old install env is inert.
|
|
41
|
+
|
|
42
|
+
Emergency/manual workaround when the MCP server environment is wrong but an existing entwurf session must be resumed: run `pi --session /path/to/entwurf.jsonl ...` from an interactive shell whose PATH is known-good. Treat this as a debug escape hatch, not a replacement for fixing the MCP launch environment.
|
|
43
|
+
|
|
44
|
+
External/meta-session semantics:
|
|
45
|
+
|
|
46
|
+
- `entwurf_v2` from a plain external host is **refused by default** (no authoritative sender — #50 C4). With the explicit `ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER=1` hatch it delivers with `origin: "external-mcp"` / `replyable: false`; there is still no reply address.
|
|
47
|
+
- `entwurf_v2` from a trusted meta-session delivers with `origin: "meta-session"`, and `replyable` is **derived from that sender's own rail — not granted by being trusted**: a self-fetch sender (Claude Code) is replyable only while its receiver is live and armed, and a native-push sender (Antigravity) only while its adapter probe finds the live conversation. Identity survives either way; only `replyable` drops to `false`. When it is `true`, `wants_reply: true` is allowed and the receiver can reply to the sender's garden id.
|
|
48
|
+
- `entwurf_v2` never launches a process, so no delivery path needs `pi` on PATH. A dormant pi target is refused as `dormant-fire-forget-unsupported`: the hidden background resume that used to answer there was withdrawn under the visible-first rule, and re-opening the session is the separate `entwurf_resume_call` verb — which DOES need `pi` on PATH, because it starts one.
|
|
49
|
+
- `entwurf_self` returns the same authoritative identity for pi sessions **and** trusted meta-sessions. A plain external host with no pi env and no trusted sender marker still fails because there is no reply address to report.
|
|
50
|
+
|
|
51
|
+
#### Claude Code
|
|
52
|
+
|
|
53
|
+
Plain MCP registration works independently of the native lifecycle. A garden-native
|
|
54
|
+
mailbox citizen requires Claude Code >=2.1.217 plus the managed meta-bridge installer;
|
|
55
|
+
older versions silently drop exec-hook arguments and are refused.
|
|
56
|
+
|
|
57
|
+
Claude Code supports both CLI registration and a separated global MCP config. The separated file is recommended for dotfile / `agent-config` workflows because `~/.claude.json` also carries OAuth-bearing state.
|
|
58
|
+
|
|
59
|
+
**Option A — CLI add:**
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
claude mcp add --scope user entwurf-bridge \
|
|
63
|
+
bash /absolute/path/to/entwurf/mcp/entwurf-bridge/start.sh
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
This writes the entry into `~/.claude.json`'s top-level `mcpServers`. Good for one-off setup; do not version-control the resulting `~/.claude.json`.
|
|
67
|
+
|
|
68
|
+
**Option B — separated `~/.mcp.json`:**
|
|
69
|
+
|
|
70
|
+
```json
|
|
71
|
+
{
|
|
72
|
+
"mcpServers": {
|
|
73
|
+
"entwurf-bridge": {
|
|
74
|
+
"type": "stdio",
|
|
75
|
+
"command": "bash",
|
|
76
|
+
"args": [
|
|
77
|
+
"/absolute/path/to/entwurf/mcp/entwurf-bridge/start.sh"
|
|
78
|
+
],
|
|
79
|
+
"env": {
|
|
80
|
+
"ENTWURF_BRIDGE_EXTERNAL_AGENT_ID": "external-mcp/claude-code"
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Claude Code reads `~/.mcp.json` in addition to `~/.claude.json`'s top-level `mcpServers`. The `env` block identifies the calling host on the receiver render — omit it and `entwurf_v2` shows `external-mcp/unknown-host`. If Claude Code permissions are locked down, allow `mcp__*` or `mcp__entwurf-bridge__*` in `~/.claude/settings.json`.
|
|
88
|
+
|
|
89
|
+
#### Codex CLI
|
|
90
|
+
|
|
91
|
+
Add the server to `~/.codex/config.toml`:
|
|
92
|
+
|
|
93
|
+
```toml
|
|
94
|
+
[mcp_servers.entwurf-bridge]
|
|
95
|
+
command = "/absolute/path/to/entwurf/mcp/entwurf-bridge/start.sh"
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
Codex has no managed citizen lifecycle (no sender marker), so this wiring can read `entwurf_peers`/`entwurf_inbox_read` but `entwurf_v2` sends are refused by default (#50 C4). To send anonymously anyway, add the explicit hatch to the same block: `env = { ENTWURF_BRIDGE_ALLOW_ANONYMOUS_SENDER = "1" }` — the send is then marked external/non-replyable (see the hatch paragraph above).
|
|
99
|
+
|
|
100
|
+
#### Antigravity CLI (`agy`)
|
|
101
|
+
|
|
102
|
+
Use the managed install surface rather than editing agy's files by hand:
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
entwurf install-agy-bridge
|
|
106
|
+
entwurf install-agy-statusline
|
|
107
|
+
entwurf install-agy-hooks
|
|
108
|
+
|
|
109
|
+
entwurf doctor-agy-bridge
|
|
110
|
+
entwurf doctor-agy-statusline
|
|
111
|
+
entwurf doctor-agy-hooks
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The three adapters deliberately own different atoms:
|
|
115
|
+
|
|
116
|
+
- bridge: one `entwurf-bridge` server in `~/.gemini/config/mcp_config.json`, plus one narrow permission string per tool the normal agy workflow calls — `mcp(entwurf-bridge/entwurf_v2)`, `mcp(entwurf-bridge/entwurf_peers)`, `mcp(entwurf-bridge/entwurf_self)` — in `~/.gemini/antigravity-cli/settings.json`. agy defaults every `mcp` action to Ask, so a tool that ships without its own rule stops for a y/n on every call; `entwurf_inbox_read` is deliberately not granted (native-push has no inbox), neither is the manual `entwurf_register_native` fallback, and neither are `entwurf_fresh_call` / `entwurf_resume_call` (both launch into the caller's own tmux session, which an agy conversation is not);
|
|
117
|
+
- statusline: the complete `statusLine` subtree pointing at the bare stable bin `entwurf-agy-statusline`;
|
|
118
|
+
- hooks: one named `PreInvocation` hook pointing at the bare stable bin `entwurf-agy-imprint`.
|
|
119
|
+
|
|
120
|
+
Unrelated servers, permissions, settings, and hooks are preserved; every adapter has a state-backed honest inverse and refuses symlink-owned SSOTs. The installer never grants broad `command(*)`, `unsandboxed(*)`, or other YOLO policy — those remain operator decisions.
|
|
121
|
+
|
|
122
|
+
The **global** MCP config live agy reads is `~/.gemini/config/mcp_config.json`. `~/.gemini/antigravity-cli/mcp_config.json` is not the global MCP root; the bridge installer one-way cleans only a stale entwurf-owned entry there. After the first model invocation, the imprint hook binds the native `conversationId` to a garden id, the statusline shows `🪛 <garden-id> agy`, and sends from that MCP child carry `agentId=meta-session/antigravity` with `replyable:true` only when the record exists and the live native-push probe succeeds.
|
|
123
|
+
|
|
124
|
+
#### External-host skills and commands
|
|
125
|
+
|
|
126
|
+
MCP registration gives the external harness the tools; the host still needs workflow guidance. Put the Mitsein-over-MCP (cross-harness collaboration) rules in that host's instruction file or, when supported, as a host-native skill. Do not assume pi slash commands are portable across external hosts — if a workflow must work across Claude Code, Codex CLI, Antigravity, and future hosts, make it a skill or MCP tool rather than a command shortcut.
|
|
127
|
+
|
|
128
|
+
For the maintained multi-harness setup and skill/command packaging details, see
|
|
129
|
+
[agent-config](https://github.com/junghan0611/agent-config). See also the
|
|
130
|
+
[concept primer](../README.md#concept-primer), the sender-envelope contract in
|
|
131
|
+
[AGENTS.md](../AGENTS.md), and [custom skills](../README.md#custom-skills).
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Fresh-cut policy
|
|
2
|
+
|
|
3
|
+
The bridge is a call relay, not a memory layer. Meta-records are routing state for
|
|
4
|
+
the **current generation**; native transcripts and external memory stores remain
|
|
5
|
+
owned by their harnesses.
|
|
6
|
+
|
|
7
|
+
## Generation contract
|
|
8
|
+
|
|
9
|
+
1. The active citizen store is **V3-only**. Garden addresses and resume authority
|
|
10
|
+
never continue across generations.
|
|
11
|
+
2. Install and citizen birth certify the active store **before writing**. Any
|
|
12
|
+
defect refuses the operation and names `entwurf meta-bridge-fresh-cut`.
|
|
13
|
+
3. A fresh cut requires proven quiescence, archives the whole active generation,
|
|
14
|
+
and opens an empty one. It never closes a session for the operator.
|
|
15
|
+
4. Archives are forensic bytes only. No runtime reads them, no restore verb exists,
|
|
16
|
+
and native transcripts and memory axes are untouched.
|
|
17
|
+
|
|
18
|
+
There is no legacy reader or migrator. A native conversation that survives a cut
|
|
19
|
+
receives a new garden id when its next trusted hook or registration births it in
|
|
20
|
+
the new generation.
|
|
21
|
+
|
|
22
|
+
## What certification checks
|
|
23
|
+
|
|
24
|
+
`certifyActiveStore` is shared by the doctor and all identity writers: pi birth,
|
|
25
|
+
Claude's `SessionStart`, agy's imprint, and `entwurf_register_native`. Every active
|
|
26
|
+
record must be:
|
|
27
|
+
|
|
28
|
+
- a regular, non-symlink `.meta.json` file;
|
|
29
|
+
- readable by the live V3 schema;
|
|
30
|
+
- named by the `gardenId` in its body;
|
|
31
|
+
- the unique owner of its `nativeSessionId`.
|
|
32
|
+
|
|
33
|
+
Previous-generation records, corruption, filename/body drift, duplicate native
|
|
34
|
+
identity, and symlinks all fail certification. Address-bearing reads additionally
|
|
35
|
+
refuse duplicate ownership before a record becomes a dispatch or resume target.
|
|
36
|
+
`entwurf_peers` keeps healthy citizens visible and reports bad entries as diagnostics;
|
|
37
|
+
it never turns an ambiguous record into authority.
|
|
38
|
+
|
|
39
|
+
Targeted mailbox and sender-marker reads enforce the per-entry half of the same
|
|
40
|
+
contract. They do not rescan the entire store on every relay operation. Record bytes
|
|
41
|
+
are opened without following symlinks; implementation and race proofs live beside
|
|
42
|
+
`readStoreRecordFile` and in the `check-meta-*` gates.
|
|
43
|
+
|
|
44
|
+
## Running a cut
|
|
45
|
+
|
|
46
|
+
First close every pi, Claude Code, and agy session that could own a citizen or
|
|
47
|
+
transport artifact. Then run:
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
entwurf meta-bridge-fresh-cut
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
Quiescence fails closed. A live control socket, a marker with a live owner, a
|
|
54
|
+
probe-alive native-push conversation, or a surface whose state cannot be proved
|
|
55
|
+
all refuse the cut before anything moves. Absence means `ENOENT`; unreadable,
|
|
56
|
+
indeterminate, or symlinked state is not treated as absent.
|
|
57
|
+
|
|
58
|
+
The one bounded exception is an impossible owner pid (`<=1` or non-integer) on the
|
|
59
|
+
certified Linux desktop/workstation axis. Current writers cannot mint such a marker,
|
|
60
|
+
so it is reported and swept as refuted legacy/corrupt residue. A harness running as
|
|
61
|
+
PID 1 is outside the certified axis and fails closed.
|
|
62
|
+
|
|
63
|
+
### Exit contract
|
|
64
|
+
|
|
65
|
+
| Exit | State | Next action |
|
|
66
|
+
|---|---|---|
|
|
67
|
+
| `0` | Cut complete | Run the appropriate installer/setup. |
|
|
68
|
+
| `1` | Nothing moved | Fix the named live, unreadable, or occupied condition and retry. |
|
|
69
|
+
| `2` | Usage error; nothing moved | Fix the command. |
|
|
70
|
+
| `3` | Transition incomplete after at least one archive move | Inspect or rerun to finish under a new stamp. |
|
|
71
|
+
| `4` | Cut complete; stale marker/socket cleanup failed | Setup may proceed, but repair the named residue first when possible. |
|
|
72
|
+
|
|
73
|
+
Only exit `0` is ordinary success. Exit `4` confirms a new generation is open but
|
|
74
|
+
still reports cleanup debt. Do not rerun an exit-4 cut after new citizens have been
|
|
75
|
+
born: that would archive the new generation too.
|
|
76
|
+
|
|
77
|
+
For the common path:
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
entwurf meta-bridge-fresh-cut && entwurf setup /path/to/project
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Upgrade order
|
|
84
|
+
|
|
85
|
+
A checkout-backed host can begin running new code immediately after `git pull`, so
|
|
86
|
+
make the boundary explicit:
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
quiesce sessions → update package/checkout → fresh-cut if prescribed → reinstall/setup → reopen
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The preflight is not a transaction or a global lock. Concurrent native births can
|
|
93
|
+
race after certification, which is why discovery and address-bearing reads still
|
|
94
|
+
check uniqueness. If a later doctor turns red, stop and preserve the store before
|
|
95
|
+
cutting again.
|
|
96
|
+
|
|
97
|
+
Source of truth: `pi-extensions/lib/meta-session.ts`, the fresh-cut implementation,
|
|
98
|
+
`check-meta-*`, and `check-fresh-cut-gate`. Historical incidents and defect chronology
|
|
99
|
+
belong in CHANGELOG/issues rather than this operator policy.
|