@junghanacs/entwurf 0.51.0 → 0.53.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.
- package/AGENTS.md +1 -1
- package/BASELINE.md +116 -397
- package/CHANGELOG.md +191 -2
- package/CONTRIBUTING.md +4 -4
- package/DELIVERY.md +2 -2
- package/ENTWURF-CLI.json +1 -1
- package/ENTWURF.json +10 -4
- package/README.md +11 -8
- package/VERIFY.md +333 -143
- package/demo/README.md +1 -1
- package/demo/demo-baseline.sh +1 -1
- package/demo/demo.sh +1 -1
- package/docs/acp-backend-rail.md +248 -34
- package/docs/setup-clean-host.md +75 -80
- package/mcp/entwurf-bridge/dist/ENTWURF.json +10 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +90 -14
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +4 -9
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +15 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/model-ids.js +9 -12
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +41 -56
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +33 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +4 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +2 -1
- package/package.json +14 -14
- package/pi/pi-durable/carrier/harness-setup.js +1 -1
- package/pi/pi-durable/carrier/subagent.js +1 -1
- package/pi/pi-durable/overlay/upstream-pin.json +15 -15
- package/pi/settings.reference.json +0 -1
- package/pi-extensions/acp-provider.ts +12 -6
- package/pi-extensions/lib/acp/acp-client.ts +6 -7
- package/pi-extensions/lib/acp/backend-adapter.ts +139 -15
- package/pi-extensions/lib/acp/backend.ts +261 -32
- package/pi-extensions/lib/acp/config.ts +4 -9
- package/pi-extensions/lib/acp/context.ts +17 -0
- package/pi-extensions/lib/acp/event-mapper.ts +236 -17
- package/pi-extensions/lib/acp/model-ids.js +9 -12
- package/pi-extensions/lib/acp/models.ts +46 -57
- package/pi-extensions/lib/acp/tool-surface.ts +34 -6
- package/pi-extensions/lib/entwurf-control-rpc.ts +5 -1
- package/pi-extensions/lib/fresh-call-composition.ts +37 -3
- package/pi-extensions/lib/herdr-fresh-call.ts +3 -1
- package/pi-extensions/lib/meta-mailbox-body.ts +1 -1
- package/pi-extensions/lib/mux-fresh-call.ts +3 -1
- package/pi-extensions/meta-bridge-pi-durable.ts +1 -1
- package/run.sh +62 -120
- package/scripts/check-acp-carrier-augment.ts +3 -21
- package/scripts/check-acp-prompt-lifecycle.ts +24 -3
- package/scripts/check-acp-provider-surface.ts +17 -26
- package/scripts/check-acp-session-reuse.ts +23 -4
- package/scripts/check-acp-stop-reason.ts +22 -3
- package/scripts/check-acp-stream-hooks.ts +24 -3
- package/scripts/check-acp-usage-accounting.ts +53 -24
- package/scripts/check-copilot-receive-arm.ts +19 -2
- package/scripts/check-entwurf-v2-surface.ts +7 -21
- package/scripts/check-fresh-call-dispatch.ts +9 -3
- package/scripts/check-gate-qualification.ts +6 -6
- package/scripts/check-herdr-fresh-call.ts +1 -0
- package/scripts/check-install-surface.ts +6 -0
- package/scripts/check-pi-durable-send.ts +4 -1
- package/scripts/check-probe-ordering.ts +34 -24
- package/scripts/check-release-gate-outcomes.ts +9 -23
- package/scripts/lib/codex-fresh-source-receipts.ts +12 -6
- package/scripts/lib/probe-cli-target.ts +3 -2
- package/scripts/mutants/acp-augment.json +0 -26
- package/scripts/mutants/acp-cortex.json +10 -183
- package/scripts/mutants/acp-foreground-only.json +11 -0
- package/scripts/mutants/acp-launch-namespace.json +3 -1
- package/scripts/mutants/acp-prompt-lifecycle.json +2 -2
- package/scripts/mutants/acp-set-model-readback.json +488 -0
- package/scripts/mutants/agent-guidance.json +2 -2
- package/scripts/mutants/codex-native.json +2 -2
- package/scripts/mutants/control-send-receipt.json +47 -7
- package/scripts/mutants/mux-fresh-call.json +12 -1
- package/scripts/mutants/pack-install.json +4 -4
- package/scripts/mutants/pi-floor.json +8 -10
- package/scripts/mutants/release-gate.json +3 -3
- package/scripts/mutants/v2-surface.json +4 -6
- package/scripts/raw-acp-compaction-measure/probe.ts +8 -2
- package/scripts/smoke-acp-cortex-live.ts +4 -408
- package/scripts/smoke-acp-ordering-probe-live.ts +7 -1
- package/scripts/smoke-acp-session-reuse-live.ts +11 -2
- package/scripts/smoke-acp-v2-send-live.ts +1 -1
- package/scripts/smoke-herdr-raw-install-live.sh +4 -4
- package/scripts/check-acp-cortex.ts +0 -710
package/VERIFY.md
CHANGED
|
@@ -1,31 +1,34 @@
|
|
|
1
1
|
# VERIFY.md
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
and the
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
3
|
+
How a live `entwurf` ACP session is verified, and what a maintainer runs before a release. Machine-checkable invariants live in gates; this file defines evidence strength, the manual judgements a gate cannot make, and release acceptance. Per-run counts, digests and release chronology belong in [BASELINE.md](./BASELINE.md), CHANGELOG and release artifacts.
|
|
4
|
+
|
|
5
|
+
VERIFY.md is the **agent-driven** surface; [BASELINE.md](./BASELINE.md) is the operator-driven one. A bridged model runs the checks and writes down what it sees. In §1B one subject verifies itself: its own description is L0, never a second identity's agreement (L1). A file, process or transcript it reads outside the bridge can reach L3 for the specific claim it corroborates. Nothing in a single session reaches L4 or L5. Verifier and subject share the same bridge, MCP servers and overlay, so a uniform corruption of those would not surface here.
|
|
6
|
+
|
|
7
|
+
### Why this exists
|
|
8
|
+
|
|
9
|
+
[BASELINE.md](./BASELINE.md) ("Why this exists") is the operator interviewing a session as a *subject*: is this still pi-shaped Claude? A session that passes is handed this file, and its role changes from the thing examined to the examiner. The Opus that passed becomes the inspector: it opens the new ACP Claude sibling or session under test, runs the walk, records what it saw, and repairs VERIFY.md where document and behavior disagree. This is the replicant-to-replicant method (the one-screwdriver idea of [힣의 드라이버](https://notes.junghanacs.com/botlog/20260423T141759); older history under "R2R" in the Appendix pointer). The 0.53.0 verification ran this way.
|
|
10
|
+
|
|
11
|
+
- §1B is written for an examiner who has already read the answers, so it asks for measurements, not recitation, and keeps every claim's evidence level.
|
|
12
|
+
- The operator drives the turns that need hands (effort, ESC, `/compact`); the walk ends with a real task and the report, because the defects that matter (#162 a silent long tool, #163 a late steer, a refused `/compact`) appeared in real work, not in the interview.
|
|
13
|
+
- Placement of the manual `/compact` cell (advisor SOL's proposal, not a gate): late in §1B, after one real read-only task and a fact/decision update, just before the report. Flow: blind BASELINE → receive VERIFY, become the examiner → real task / changed decision → manual `/compact` → the next real step → report.
|
|
14
|
+
|
|
15
|
+
**Who executes what.**
|
|
16
|
+
|
|
17
|
+
- **Part I — verifying a live session.** An ACP subject asked to verify itself reads **Part I only**, from the top to the `# Part II` heading (Evidence Levels, §1B, §1A, §0, Continuity notes, §2), and executes **§1B only**. §1A, §0 and §2 tell it what is being judged. It opens Part II only when a step points there.
|
|
18
|
+
- **Part II — the maintainer floor.** The subject does not read it up front and does not run any of it: §0A (where a check lives, the floors, release axes), §1 Setup, §3 release criteria, or any `LIVE=1` command. Where §1B and Part II seem to disagree on what to run, §1B.0 wins for the subject.
|
|
19
|
+
- **Appendix.** Troubleshooting, the old banner's dated numbers and history pointers.
|
|
20
|
+
|
|
21
|
+
> **Current surface.** `entwurf-bridge` exposes nine tools: `entwurf_v2`, `entwurf_peers`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_retire_call` (operator-requested target only), `entwurf_callback`, `entwurf_self`, `entwurf_inbox_read` and `entwurf_register_native`. A native pi citizen offers seven of them (two hidden), and the pi-durable contact offers eight. An ACP session's own count is measured from its schema (§1B.3). The supported ACP backend is Claude; Cortex ACP is disabled. Antigravity and Codex are native-push citizens outside ACP; Antigravity's native push is paused (#152).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# Part I — Verifying a live session
|
|
23
26
|
|
|
24
27
|
## Evidence Levels
|
|
25
28
|
|
|
26
29
|
Every claim — and every History entry — sits on one of these rungs. Make the rung explicit so neither narrative nor reader overreaches.
|
|
27
30
|
|
|
28
|
-
> **Namespace note.** These `L0–L5` rungs measure *evidence quality* for bridge verification. Native async delivery has its own capability namespace `D0–D8` in [DELIVERY.md](./DELIVERY.md); operator-driven identity baseline
|
|
31
|
+
> **Namespace note.** These `L0–L5` rungs measure *evidence quality* for bridge verification. Native async delivery has its own capability namespace `D0–D8` in [DELIVERY.md](./DELIVERY.md); the operator-driven identity baseline in [BASELINE.md](./BASELINE.md) had its own `Q-L1..Q-L5` *surface-isolation layers* (retired rounds, now in [docs/baseline-receipts.md](./docs/baseline-receipts.md)). Same letters, different axes — do not conflate "high-quality evidence" with "high delivery capability".
|
|
29
32
|
|
|
30
33
|
| Level | What it is | Closes | Does not close |
|
|
31
34
|
|---|---|---|---|
|
|
@@ -40,6 +43,277 @@ When you write a new entry, mark its rung. "L1 only" is honest; "L2 reached" is
|
|
|
40
43
|
|
|
41
44
|
---
|
|
42
45
|
|
|
46
|
+
## 1B. ACP self-run walk — the subject verifies itself, with the operator driving
|
|
47
|
+
|
|
48
|
+
This is the section an ACP subject executes when the operator says "read VERIFY.md and run the checks yourself." The subject is the model in the operator's own resident session (on 2026-11-13: `entwurf/claude-opus-5-5` in GLG's `entwurf pi` session, run from a development checkout installed as the operating owner). It replaces the hand-run single-turn / multi-turn / scenario sections of the pi-shell-acp era (git `fc5e095`), keeping their shape — snapshot, turn map, inject → recall → update, real work, hygiene — and dropping their retired verbs, version counts and cross-process claims.
|
|
49
|
+
|
|
50
|
+
The walk runs inside **one** existing session. The operator sends every turn; the subject proposes the next prompt and records what it saw, but never opens another session to play the operator. BASELINE's question bank is the operator's blind pass and comes first; this walk comes after, so the subject has read the answers here and must earn each claim with a measurement rather than by repeating this document.
|
|
51
|
+
|
|
52
|
+
### 1B.0 Ground rules
|
|
53
|
+
|
|
54
|
+
- **Allowed — a closed list.** Anything not on it, whether a command, a `run.sh` verb or an MCP call, needs the operator's instruction in this session. The list: reading files and source; read-only shell (`ls`, `cat`, `grep`, `git log/show/status`, `ps`, `readlink`, `jq`); `entwurf_self` and `entwurf_peers`; the read-only doctors and the deterministic gates named in §1B.2 and §1B.9; writing scratch files under a directory the operator names, outside the checkout.
|
|
55
|
+
- **Named examples of what is not on that list:**
|
|
56
|
+
- Installing or building: `setup`; any `install-*`/`uninstall-*`/`takeover-*`/`wire-*`/`register-*`/`herdr-plugin-*`; `plugins/herdr/use-dev-checkout.sh`; `pnpm install`; `pnpm run build-bridge` or any build. On a host where this checkout is the operating owner, the gitignored `dist/` is what Pi's built-in bridge loads, while the ACP-side bridge runs `src/` through `mcp/entwurf-bridge/start.sh`; both are live.
|
|
57
|
+
- Rewriting the meta store: `meta-bridge-prune`, `meta-bridge-fresh-cut`.
|
|
58
|
+
- Everything else: anything prefixed `LIVE=1`, `release-gate`, `pnpm run check:full`, `entwurf_fresh_call`, `entwurf_resume_call`, `entwurf_retire_call`, `entwurf_register_native`, `entwurf_callback`, `entwurf_inbox_read` (its garden id is caller-supplied and unverified, so another id drains that citizen's mail), an `entwurf_v2` send to anyone, a Cortex/agy/Codex call, `git commit`/`push`, editing any file in the checkout, the operator's profile, settings, hooks or overlay.
|
|
59
|
+
- **Never:** reading, printing or copying credentials (`auth.json`, `.env*`, tokens); killing or signalling a process; deleting records, transcripts or caches; another session's transcript or record beyond the facts `entwurf_peers` already returns.
|
|
60
|
+
- **Transparent mode:** verification here is not a benchmark. Use short turns. When something looks wrong, stop, say what was expected and what was seen, and wait for the operator. A failure is reported, not repaired.
|
|
61
|
+
- **Evidence rung on every line** (Evidence Levels above): your own description is L0; an MCP call's returned payload is L2 for that call only; a file, process or transcript read outside the bridge is L3 only for the specific claim it independently corroborates, and otherwise is just what you observed. The operator's own observation is theirs, and you report it as theirs. Do not promote a rung because several weak observations agree.
|
|
62
|
+
|
|
63
|
+
### 1B.1 Turn map
|
|
64
|
+
|
|
65
|
+
The operator sends these in order; one turn may cover several steps if they are short. Numbering is for the report, not a script.
|
|
66
|
+
|
|
67
|
+
| Turn | Step | Operator does |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| 1 | §1B.2 snapshot | "run the snapshot" |
|
|
70
|
+
| 2 | §1B.3 self-recognition, measured | "now check your claims against the files" |
|
|
71
|
+
| 3 | §1B.4 a code word to hold (inject) | gives a harmless code word and one fact |
|
|
72
|
+
| 4–5 | §1B.5 real read-only work on this repository | names a question about the code |
|
|
73
|
+
| 6 | §1B.4 recall, then update the fact | "what was the code word and fact?" then changes the fact |
|
|
74
|
+
| 7 | §1B.6 effort | changes the thinking level in pi's selector, then sends a short turn |
|
|
75
|
+
| 8 | §1B.7 abort | sends a turn that runs a while, presses ESC, then sends one more turn |
|
|
76
|
+
| 9 | §1B.4 recall after the abort | "the code word, and the latest fact?" |
|
|
77
|
+
| 9b | §1B.7a manual `/compact`, then the next real step | types `/compact` once the context is large enough, then sends the next step of the work |
|
|
78
|
+
| 10 | §1B.8 transcript axis and hygiene | "look at your own transcript and processes" |
|
|
79
|
+
| 11 | §1B.9 deterministic gates (optional) | names which gate, if any |
|
|
80
|
+
| 12 | §1B.10 report | "write the report" |
|
|
81
|
+
|
|
82
|
+
Turns 7 and 8 need the operator's hands, and the operator may skip them; a skipped step is reported as not measured, never as passed.
|
|
83
|
+
|
|
84
|
+
### 1B.2 Snapshot (L3)
|
|
85
|
+
|
|
86
|
+
Collect, and report each line with its command:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
readlink -f "$(command -v entwurf)" # which install owns the bin
|
|
90
|
+
git -C <that checkout> log -1 --format='%h %s' # source revision, when the owner is a checkout
|
|
91
|
+
git -C <that checkout> status --short | head # clean or not
|
|
92
|
+
pi --version
|
|
93
|
+
jq -r .version <checkout>/node_modules/@agentclientprotocol/claude-agent-acp/package.json
|
|
94
|
+
jq -r .version <checkout>/node_modules/@agentclientprotocol/sdk/package.json
|
|
95
|
+
<checkout>/run.sh doctor-pi-package # who owns the Pi user-scope registration
|
|
96
|
+
<checkout>/run.sh doctor-pi-provider # does the provider's bridge command boot
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
Then call `entwurf_self` and report `sessionId`, `origin`, `cwd`, and its rail fact: a pi session reports `socketState`, while `rail` appears only for a meta-session citizen. The meta record `~/.pi/agent/meta-sessions/<sessionId>.meta.json` gives `nativeSessionId`; your transcript is `~/.pi/agent/sessions/--<cwd with / as ->--/*_<nativeSessionId>.jsonl`. Find your own pi process and the ACP child under it, and report PIDs, parent PIDs and executable names only. Other processes' argv can carry other people's tasks, so do not print the host-wide argv list:
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
ps -o pid,ppid,etimes,comm -p "$PPID" # walk up from your own shell with -p <ppid> until pi
|
|
103
|
+
ps -o pid,ppid,etimes,comm --ppid <your pi pid> # its direct children; the ACP child is one of them
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
For a PID on your own chain, or a direct child of your own pi process (for example the `entwurf-bridge` MCP server pi itself starts), you may read its argv (`ps -o args= -p <pid>`), because pi and the ACP child may both show `node` as their name. Without that, a chain you cannot walk with certainty is reported as unknown.
|
|
107
|
+
|
|
108
|
+
`doctor-meta-bridge` is the Claude Code native-citizen doctor; it is not about this ACP session. It is read-only toward the operator, but one of its checks delivers a test message inside a temporary world, so run it only when the operator asks.
|
|
109
|
+
|
|
110
|
+
Pass: every line answered from a command; a version or path you could not read is reported as unknown. Fail: a version or owner stated from this document or from memory.
|
|
111
|
+
|
|
112
|
+
### 1B.3 Self-recognition, measured
|
|
113
|
+
|
|
114
|
+
Answer first, then check each answer against a source outside yourself:
|
|
115
|
+
|
|
116
|
+
1. **Harness and backend:** you are a Claude model reached through Pi's `entwurf` provider over ACP (`claude-agent-acp`), not Claude Code started directly. Corroborate with the process tree from §1B.2.
|
|
117
|
+
2. **Native tools:** list the native tools your callable schema carries, then compare with `DEFAULT_CLAUDE_TOOLS` and `DEFAULT_CLAUDE_DISALLOWED_TOOLS` in `pi-extensions/lib/acp/tool-surface.ts` and the `Skill` rule in `pi-extensions/lib/acp/config.ts`. Report differences; your schema wins over the file.
|
|
118
|
+
3. **MCP:** list the MCP servers and tools your schema carries, verbatim (`mcp__entwurf-bridge__entwurf_v2` shape, §2.1). Compare the server names with `entwurfProvider.mcpServers` in `<cwd>/.pi/settings.json` and `~/.pi/agent/settings.json`, reading names only (`jq -r '.entwurfProvider.mcpServers // {} | keys[]'`); a server's `env` or args may hold secrets and are not printed. If names alone cannot be read, report the comparison as not measured. Report the count you see; it is not required to match another rail's count.
|
|
119
|
+
4. **Carriers (§1A.0):** say what came through the engraving slot and what came through the first-user augment. Compare the engraving with `pi-extensions/lib/acp/prompts/engraving.md` (or the file `ENTWURF_ACP_ENGRAVING_PATH` names), and the augment with `buildPiContextAugment` and `prependNewPromptAugment` in `pi-extensions/lib/acp/augment.ts` and with which AGENTS files exist for your cwd.
|
|
120
|
+
5. **Input:** the `entwurf` rows declare text-only input (`ACP_ROW_INPUT` in `pi-extensions/lib/acp/models.ts`). Say what that means: no path carries image bytes to the backend, and an image block pi does pass to the converter becomes `[image omitted: <mime>]` in the rebuilt or delta prompt (`context.ts`). Whether pi's UI passes an attachment on a text-only row at all is unmeasured; if the operator tries it, report only what you received.
|
|
121
|
+
|
|
122
|
+
Pass: answers match their sources, and "I cannot tell" where no source answers. Fail: a tool, server or carrier content that no source shows; the bridge-identity narrative attributed to the engraving.
|
|
123
|
+
|
|
124
|
+
### 1B.4 Continuity — bridge and semantic, kept apart
|
|
125
|
+
|
|
126
|
+
- **Inject (turn 3):** the operator gives a code word and one plain fact (Continuity notes, wording rule: animal, colour or place names, never anything that sounds like a secret). Repeat them once, exactly.
|
|
127
|
+
- **Recall (turn 6):** return the code word verbatim and the fact, then accept the operator's update to the fact.
|
|
128
|
+
- **After the abort (turn 9):** return the code word and the *updated* fact.
|
|
129
|
+
- **Bridge side:** read the `[acp: …]` notices pi stored in an assistant message in your transcript (§1B.8). You cannot see them otherwise: they are display-only and are not sent back to you. Read them for the *previous* turn, never the one you are generating, which is not yet settled in the file; the operator sees the current turn's notices on screen. A first-turn `preparing` notice is visible only if this session's file still holds that turn. Notices are bridge-side evidence, not an independent proof of the backend's own session state. In a resident session the first turn shows `[acp: preparing claude session]`, then `[acp: session ready model=<id>]`, and later turns show `[acp: reusing live session]` while the session lives. A sibling opened by `entwurf_fresh_call` runs the same resident lifecycle and showed the same shape (n=1, 2026-11-13). A changed effort does not by itself open a new session: on reuse the new level is set and read back on the live session. A new session (`preparing` again, transcript resent as text) follows only when the session was dropped: a refused or mismatched effort answer, a first-turn cancel, an escalation or pre-prompt abort, a child death, or a changed bridge configuration. The model is locked for an `entwurf` session (§Appendix, model guard).
|
|
130
|
+
|
|
131
|
+
Pass: semantic recall right on every recall turn, and the bridge reading explains any new session it shows. Fail: a recall that paraphrases the code word; a claim of reuse that the notices contradict.
|
|
132
|
+
|
|
133
|
+
### 1B.5 Real read-only work (Layer 1)
|
|
134
|
+
|
|
135
|
+
The operator names a question about this repository, for example: "where is the effort read-back notice produced, and which gate certifies it?" or "what does an ESC leave behind on a reuse turn, and where is that text?" Answer with `file:line` references you actually opened. Use `Bash` for search (`grep -rn`); there is no `Grep` tool on this surface.
|
|
136
|
+
|
|
137
|
+
Pass: every reference opens to what you said; no recursive `pi` and no MCP detour for a file read. Fail: a reference you did not open; an answer from memory.
|
|
138
|
+
|
|
139
|
+
### 1B.6 Effort (#142)
|
|
140
|
+
|
|
141
|
+
Claude ACP rows map pi's thinking levels onto the agent's `effort` option of the same name (`CLAUDE_ACP_EFFORT_VALUES`, `claudeAcpThinkingLevelMap` in `models.ts`). Which of `low`..`max` a row offers is decided by pi's registry for that model: `xhigh`/`max` appear only where the registry maps them, and `off`/`minimal` are never offered. The level is set and read back after set-model on a new session, and on a reused session only when it changed; the transcript then carries `[acp: effort <value> read back]` before `sending prompt` (`backend.ts`). A refused or mismatched answer fails the turn before the prompt with `acp-thinking-level-unsupported` or a readback error, and drops a reused session.
|
|
142
|
+
|
|
143
|
+
A session's first effort is the pi thinking level in force when it starts: `defaultThinkingLevel` in pi settings, unless the operator changed it in the selector before the first turn (those changes are `thinking_level_change` entries in the transcript). After the operator changes the level (turn 7), report the value read back from that turn's notice. Read it in turn 8 or later, once turn 7 has settled in the transcript; until then it is the operator's on-screen observation. Readback proves the agent accepted the setting. It is not evidence of applied reasoning depth or speed, so do not report on how hard you thought.
|
|
144
|
+
|
|
145
|
+
### 1B.7 Abort (#142)
|
|
146
|
+
|
|
147
|
+
ESC sends ACP `session/cancel`; the agent ends its own turn, and only after a bounded grace does process cleanup follow. After an ESC the turn carries one of two notices, defined as `ACP_CANCEL_KEPT_NOTICE` / `ACP_CANCEL_CLOSED_NOTICE` in `backend.ts`; `pushAcpLifecycleNotice` in `event-mapper.ts` wraps them as `[acp: …]` on screen:
|
|
148
|
+
|
|
149
|
+
- `stopped — changes already made stay; next message continues this session` — a reuse turn the agent closed on cancel;
|
|
150
|
+
- `stopped — changes already made stay; next message opens a new session` — a cancelled first turn, an escalation, or an abort before the prompt was sent.
|
|
151
|
+
|
|
152
|
+
When the next turn rebuilds the transcript, an aborted assistant turn is followed by `[turn status: aborted — actions this turn had started may already have taken effect; cancellation is not rollback]` (`context.ts`). The reuse delta carries no such line.
|
|
153
|
+
|
|
154
|
+
For turn 8 the operator should send something harmless that takes a few seconds, such as reading several files, never an edit, and should not change the effort level in the same turn: an ESC landing while a changed effort is being set is a pre-prompt abort and closes the session, which mixes two readings. After ESC, report which notice appeared, whether turn 8b reused or opened a session, and whether anything the cut turn started may have happened. Do not claim that a cut undid anything.
|
|
155
|
+
|
|
156
|
+
### 1B.7a Manual `/compact` (#163)
|
|
157
|
+
|
|
158
|
+
Only the operator can type `/compact` (Pi handles it from interactive input; a message-driven walk cannot). Long answers that live only in tool input are not in Pi's estimate; ask for them as assistant text. Send it late, after the real task (§1B.5) and the fact update (§1B.4), then continue the work. **The cell's last action is that next real step**, not `/compact`: does the continuation keep latest decision, remaining work and finished work distinct?
|
|
159
|
+
|
|
160
|
+
**Pi must have something to cut.** Pi refuses before any model call with `Already compacted` (last entry is a compaction) or `Nothing to compact (session too small)` (`agent-session.js:2339-2346`, `compaction.js:609-612,642`, pi-coding-agent 1.5.2). The gate is Pi's own transcript text, not Claude's occupancy: `estimateTokens` (UTF-16 chars/4) summed from the newest message back must reach `keepRecentTokens` (default 20000, `settings-defaults.js:10-11`; model and project overrides `settings-manager.js:654-669`; `compaction.js:555-578`). Measured by 02055a on the installed pi: the estimate after the first user message must be ≥ 20000 (19999 → nothing to compact; exactly 20000 compacts only the first prompt). Aim for ≥ 30000 (about 80,000 characters, better 120,000; one Hangul character counts 1). Counted: user text, assistant text/thinking, signed `[acp: …]`/`[tool:…]` lines; not counted: the Claude child's tool I/O. The footer % is Claude-side occupancy (`event-mapper.ts:565-577`) and is not the criterion. If the automatic threshold or Claude's native compaction fires, log it as a separate cell.
|
|
161
|
+
|
|
162
|
+
**Observe** (each row its own rung; UNMEASURED never counts as PASS):
|
|
163
|
+
- **c0 shape.** ACP turns are short prompts with long answers, so the cut usually splits a turn and Pi calls the summarizer twice (`compaction.js:688-703`): up to two quiet summary children. Tests drive one request only. Record the verdict, `summarize`, `turnPrefix` and `splitTurn`.
|
|
164
|
+
- **c1 summary clean.** In the last `compaction` entry of the Pi session file, `summary` has no `[acp:`, `[tool:`, ANSI or C0 characters and `fromHook` is false. Pi's own split joiner (`**Turn Context (split turn):**`) is not contamination; `<read-files>`/`<modified-files>` should be empty on ACP.
|
|
165
|
+
- **c2 old child closed before the next prompt.** Note the claude-agent-acp pid(s) under the Pi process before `/compact`; after it and before the next prompt they are gone, summary children appear then vanish, and no `[acp: … unexpected end]` line shows (`acp-provider.ts:70` → `backend.ts:483`). Look only, never kill. Checking after the next turn cannot discriminate. No `/new` or fork inside the cell.
|
|
166
|
+
- **c3 next turn starts from the summary.** First line `[acp: preparing claude session]`, not `[acp: reusing live session]`; the new child's first user message has the augment, then a block `User: The conversation history before this point was compacted…` and the kept tail.
|
|
167
|
+
- **c4 continuation.** The next real step; ask for the code word planted in turn 1; record whether decisions, remaining and finished work stayed distinct. A quality observation, not plumbing proof.
|
|
168
|
+
- **c5 O6 `tools: []`.** Record exactly: "delivery path read + non-use observed (summary child transcript has 0 `tool_use`, ended `end_turn`); the provided tool set is unobserved." The ACP wire does not expose it; a stronger check is a separate LIVE probe that needs GLG's approval.
|
|
169
|
+
- **c6 (optional) cancel.** ESC during `/compact` shows `Compaction cancelled`: no compaction entry, no leftover summary child.
|
|
170
|
+
|
|
171
|
+
**Recording.** Header: n=1, host, date, pi 1.5.2, claude-agent-acp 0.107.0, model id, effective `keepRecentTokens` with its source. States: PASS / FAIL / PARTIAL / UNMEASURED.
|
|
172
|
+
- Not attempted: `UNMEASURED — not attempted`. `Nothing to compact`: `UNMEASURED — Pi gate not reached: estTokensAfterFirstUser=<n> < keepRecentTokens=<k>`, with the pre-check result and footer % side by side. `Already compacted`: this attempt UNMEASURED.
|
|
173
|
+
- Compacted but an observation missed: only that row is PARTIAL, with the reason. A summary-turn `error` stop is FAIL with the raw reason; repair nothing.
|
|
174
|
+
- Fixture or source passes (`backend.summary-turn.test.ts`) never stand in for this session's compact; success at a short context is not long-context durability, so state the context reached.
|
|
175
|
+
- Pre-check (read-only, Pi's own `prepareCompaction` on the session file) and its output live in [docs/baseline-receipts.md](./docs/baseline-receipts.md) (read on GitHub).
|
|
176
|
+
- Usage record (advisor note, never a gate): after a normal job the operator may ask three things — what was Claude doing while I waited; after ESC could I resume knowing the state; after compact were decisions, remaining and finished work distinguishable. Note discomfort as task / screen / observation / remedy.
|
|
177
|
+
|
|
178
|
+
### 1B.8 Transcript axis and hygiene (L3)
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
F=$(ls ~/.pi/agent/sessions/--*--/*_<nativeSessionId>.jsonl)
|
|
182
|
+
jq -r '.message.role // .type' "$F" | sort | uniq -c
|
|
183
|
+
jq -r 'select(.message.role=="assistant") | .message.content[]? | select(.textSignature=="entwurf:lifecycle-notice-v1") | .text' "$F" | grep . # signed display lines: lifecycle notices AND #163 tool lines/previews; add `| select(startswith("\n[acp:"))` for notices only (a model's own "[acp: …]" carries no signature); grep . drops the blank lines each notice is wrapped in
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
- Pass: user and assistant turns accumulate in your own pi transcript. A message a sibling delivers through `entwurf_v2` is stored as `custom_message`, not `user`, so when an operator drives the walk by message the `user` count will not match the turn count. Under ACP the memory axis is still pi's file, and no second memory layer exists. There is no separate child pi transcript in a resident session.
|
|
187
|
+
- **Processes:** report the ACP children under your own pi process now. Use one alive child per live `(sessionKey, backend, modelId, bridgeConfigSignature)` as the expected bound (§2.3). Without a "before" count, the delta is unmeasured. A process name alone does not prove ownership or orphanhood. Look only, and never kill.
|
|
188
|
+
|
|
189
|
+
### 1B.9 Deterministic gates (optional, operator's pick)
|
|
190
|
+
|
|
191
|
+
Deterministic gates are designed to run offline with a sandboxed HOME, `PI_CODING_AGENT_DIR` and XDG roots (AGENTS.md Verification), but a subject should not take that as a blanket guarantee. Run one only when the operator names it in this session:
|
|
192
|
+
|
|
193
|
+
- `./run.sh check-acp-set-model-readback` covers model readback, effort and the cancel notices; `./run.sh check-acp-vendor-rejection` covers the reuse turn's cooperative cancel (`ACP-REUSE-COOPERATIVE-CANCEL`). Running it runs the fixture tests, not their mutants; mutant kill-power is a separate PARTIAL qualification (`scripts/mutants/acp-set-model-readback.json`), which is a maintainer action.
|
|
194
|
+
- `./run.sh check-acp-carrier-augment`, `check-acp-tool-surface` and `check-acp-config` cover the carriers, the tool surface and the MCP projection.
|
|
195
|
+
- `pnpm check` is the core tier, about a minute on the reference host.
|
|
196
|
+
|
|
197
|
+
A green gate certifies its fixture contract, not this live session, so report it beside the live observations, not as one of them. `pnpm run check:full` (about 16 minutes) and every `LIVE=1` gate belong to the maintainer floor (§3) and are not part of this walk.
|
|
198
|
+
|
|
199
|
+
### 1B.10 Report
|
|
200
|
+
|
|
201
|
+
The report is one table, then findings:
|
|
202
|
+
|
|
203
|
+
| Step | Observed | Evidence (command / `file:line` / transcript line) | Rung | Verdict |
|
|
204
|
+
|---|---|---|---|---|
|
|
205
|
+
|
|
206
|
+
- **Verdicts:** use `pass`, `fail`, `not measured` or `operator-judged` (the operator saw it; you did not).
|
|
207
|
+
- **Findings:** classify each one as **Blocker**, **Defect** or **Observation** (AGENTS.md Review Discipline). Name the source line that disagrees.
|
|
208
|
+
- **Evidence source:** a row whose Evidence column is empty, or whose only source is VERIFY.md itself, gets `not measured`. This document tells you what to look for, but it is not the evidence.
|
|
209
|
+
- **Boundary:** end with what this walk cannot show. Verifier and subject are one session on one bridge, so the walk stays below L4. It is n=1. Readback is not reasoning depth. There is no long-haul soak (L5).
|
|
210
|
+
|
|
211
|
+
Return the report to the operator in the session. Send it nowhere else unless the operator says so.
|
|
212
|
+
|
|
213
|
+
### 1B.11 When an examiner runs the walk on a sibling
|
|
214
|
+
|
|
215
|
+
The original protocol has an ACP examiner open a fresh ACP sibling and walk it through the core interview and §1B (2026-11-13: Opus examining Sonnet). A subject's answer is L0 until the examiner has re-measured it from outside the subject:
|
|
216
|
+
|
|
217
|
+
- **Process chain:** the examiner's own `ps` of the subject's pi, ACP child and `claude`.
|
|
218
|
+
- **Record:** the subject's meta record (`nativeSessionId`, `backend`) read by the examiner.
|
|
219
|
+
- **References:** a sample of the subject's `file:line` references, opened by the examiner.
|
|
220
|
+
- **Transcript:** role counts and signed notices from the subject's transcript once its turn has settled. A turn the examiner delivers by `entwurf_v2` is stored there as `custom_message`.
|
|
221
|
+
|
|
222
|
+
A fresh sibling's first message is its `entwurf_fresh_call` task, so that task carries the blind core interview. Keep it to the interview block plus one reply instruction, and grade the routing words as part of what arrived.
|
|
223
|
+
|
|
224
|
+
---
|
|
225
|
+
|
|
226
|
+
## 1A. Main Agent Evaluation — Is `entwurf` Claude strong enough?
|
|
227
|
+
|
|
228
|
+
Separate from continuity gates. Gates prove "sessions continue"; this questionnaire examines tool self-awareness / native tool usability / MCP-boundary awareness / long-turn focus / quality vs direct Claude Code. The current subject is whichever curated `entwurf/<model>` row the operator has opened in a resident `entwurf pi` session (on 2026-11-13 GLG's `entwurf/claude-opus-5-5`); turns accumulate in that one session as the operator sends them. A one-shot `pi --provider entwurf … -p` is turn-scoped (§0 criterion 1), so it cannot run Layer 3 and is not how this questionnaire is driven. §1B turns these layers into a step-by-step walk the subject runs on itself.
|
|
229
|
+
|
|
230
|
+
### 1A.0 Two carrier surfaces — engraving vs pi-context-augment (load-bearing)
|
|
231
|
+
|
|
232
|
+
`entwurf` delivers identity-relevant text through **two structurally distinct surfaces**. Collapsing them into "the system prompt" is the most common verifier-side mistake. (BASELINE Q-B0 and Q-B0-CARRIER grade the same separation operator-side.)
|
|
233
|
+
|
|
234
|
+
| Surface | Source | Delivery shape | Default content |
|
|
235
|
+
|---|---|---|---|
|
|
236
|
+
| **Engraving carrier** | `pi-extensions/lib/acp/prompts/engraving.md` (or `ENTWURF_ACP_ENGRAVING_PATH`) | Claude `_meta.systemPrompt` — full-replacement identity slot | Operator-authored, optional opt-out; tiny non-empty by default on Claude ACP (replaces the `claude_code` preset + strips its auto-memory advertisement). Emptying the file is the opt-out. |
|
|
237
|
+
| **pi-context-augment** | `pi-extensions/lib/acp/augment.ts` (`buildPiContextAugment`, prepended by `prependNewPromptAugment`) | First-user-message prepend (not the system slot) | Always carries (1) the bridge identity line and the tool-truth rule ("the actual callable schema is the source of truth"). Then, each only when the file exists and is non-empty: (2) `~/AGENTS.md`, (3) the cwd's `AGENTS.md` when it differs from the home one. The whole augment is cut at 50 KiB with a visible `[entwurf: context augment truncated …]` marker, so a long home file can push the cwd block out entirely, and a cwd block the prompt already carries is dropped from the augment rather than sent twice (`truncateAugment`, `prependNewPromptAugment`). |
|
|
238
|
+
|
|
239
|
+
Pass (carrier honesty): the subject distinguishes engraving from pi-context-augment by name or structure without prompting; on ACP targets says which augment components arrived, given which AGENTS files exist for its cwd (a missing component is a fail only when its file exists and is non-empty, the truncation marker is absent, and the prompt did not already carry that cwd block); may quote the engraving but must **not** attribute bridge identity / AGENTS / memory policy to it. Fail: attributes the bridge-identity narrative to the engraving carrier; claims the augment is empty on an ACP run; invents engraving content. Native pi exception: on native targets the bridge-identity line and `~/AGENTS.md` are not part of the augment — the PASS criterion is honesty about what arrived, not the three-component checklist.
|
|
240
|
+
|
|
241
|
+
### 1A.1 Layers
|
|
242
|
+
|
|
243
|
+
- **Layer 0 — self-awareness:** ask environment self-awareness / MCP visibility / upstream-instruction awareness, guessing prohibited. Pass: recognizes native tool family, says "I don't know" honestly, answers MCP visibility only as configured, describes upstream instruction type without reproducing internal prompts. Fail: claims a nonexistent tool, conflates pi-custom and native tools, hallucinates MCP visibility, or conflates the two carriers (§1A.0).
|
|
244
|
+
- **Layer 1 — native tool use:** throw file-reading / structure-analysis / regression-hunting tasks. The Claude ACP default native surface is `Read`/`Bash`/`Edit`/`Write`, plus `Skill` when skill plugins are configured (`DEFAULT_CLAUDE_TOOLS` in `pi-extensions/lib/acp/tool-surface.ts`, `config.ts`); there is no `Grep`/`Glob`, so search goes through `Bash`. The session's actual callable schema is the truth, not this sentence. Pass: tool selection is natural for that surface; no detour through MCP or recursive `pi`. Fail: strange detours for simple reads; speaks from memory without reading; claims a tool its schema does not carry.
|
|
245
|
+
- **Layer 2 — MCP boundary:** the ACP session sees exactly the MCP servers the operator declared in `entwurfProvider.mcpServers` (global and project settings merged per name; on this checkout the project declares `entwurf-bridge`), and the verbs that server lists. How many entwurf verbs the ACP projection shows is measured from the session's own callable schema; do not carry over the native-Pi (seven, two hidden) or pi-durable (eight) counts, which are other rails. Changing the declaration changes `bridgeConfigSignature`, so a live incompatible session is replaced rather than silently reused (`check-acp-config`, `smoke-acp-mcp-live`). A declared server with no callable tool in the schema is reported as exactly that; whether it is connected, and why it shows nothing, stays undetermined. Pass: names only servers and tools its schema carries; explains the native-vs-MCP boundary; treats `entwurf_register_native` as binding an already-running conversation (today Antigravity only, and paused by #152), never as fresh spawn. Fail: pretends to use an unseen tool; mimics entwurf via recursive `pi`.
|
|
246
|
+
- **Layer 3 — focus across turns:** inject a fact, then accumulate turns mixing retrieval/exploration. Pass (a heuristic carried over from the pi-shell-acp era, not a release threshold): after **8 turns** holds **3+ early facts** incl. **one verbatim string injected before turn 5**; no repeated exploration, no self-contradiction, no tool-strategy drift. Fail: forgets early reads; paraphrases instead of returning the verbatim string. Note: entwurf exposes no user-facing compaction; use the backend's `usage_update` footer as an overflow-risk signal (it follows the ACP backend's `used/size`, not pi's visible-transcript estimate).
|
|
247
|
+
- **Layer 4 — vs direct Claude Code (operator-only; the subject cannot run it alone):** requires a verifier holding **both** the `entwurf` and a direct path (human-in-loop, or both transport handles). Compare latency / native tool accuracy / detours / boundary confusion / quality around turns 10–15. Repeated tool confusion, long-turn forgetting, or boundary workarounds are a fail.
|
|
248
|
+
|
|
249
|
+
Interpretation: Layers 0–2 healthy → basic qualifications confirmed. Layer 3 weak → strengthen prompt shape + corroborate with bootstrap logs / process state / sentinel recall. Layer 4 much weaker than direct → revisit bridge handoff. This questionnaire does not replace gates.
|
|
250
|
+
|
|
251
|
+
---
|
|
252
|
+
|
|
253
|
+
## 0. Quality Criteria
|
|
254
|
+
|
|
255
|
+
The goal is not merely "invoke Claude Code." We want:
|
|
256
|
+
|
|
257
|
+
1. **Session continuity at the agent-shell level** — only a resident pi (`--entwurf-control`, which `entwurf pi` adds) is process-scoped and reuses one live ACP session, each later turn sending only the new user message; plain interactive `pi` and `pi -p` are turn-scoped and open a new ACP session every turn, carrying pi's transcript rendered as one text prompt (`context.ts`) — a text rendering, never a backend-native transcript hydration (`resolveLifecyclePolicy`, `pi-extensions/lib/acp/session-store.ts`; [docs/acp-backend-rail.md](./docs/acp-backend-rail.md)).
|
|
258
|
+
2. **Preservation of pi harness semantics** — pi session files / transcripts / memory pipeline stay a shared axis.
|
|
259
|
+
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.
|
|
260
|
+
4. **Thin bridge** — no second harness built inside this repo.
|
|
261
|
+
5. **Explicit capability boundary** — pi custom tool / user MCP visibility is determined solely by `entwurfProvider.mcpServers`; no automatic `~/.mcp.json` loading.
|
|
262
|
+
6. **Operational hygiene** — no orphan subprocesses, no excess persisted session garbage.
|
|
263
|
+
|
|
264
|
+
## Continuity notes
|
|
265
|
+
|
|
266
|
+
### Wording — avoid safety-interpretation contamination
|
|
267
|
+
|
|
268
|
+
When injecting a fact for a continuity check, use **plaintext that does not trigger model safety interpretation**. Avoid `secret token`, `password`, `API key`, `credential`, and meta-directives like "do not leak" — such wording makes the model treat the prompt as an exfiltration attempt and refuse, which makes **continuity look broken even when it is alive** (this happened once with `test-token-123`, misdiagnosed as a delegation failure). Instead: `The code word is owl → reply in one word → owl`; code names / colors / animal names. Do not mix continuity and safety-behavior verification in one prompt.
|
|
269
|
+
|
|
270
|
+
### bridge continuity vs semantic continuity
|
|
271
|
+
|
|
272
|
+
- **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.
|
|
273
|
+
- **semantic continuity:** a fact from a prior turn is retrievable in a later turn.
|
|
274
|
+
|
|
275
|
+
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 read the turn's own lifecycle notices in the assistant text (`[acp: preparing …]` on a new session, `[acp: reusing live session]` on reuse). `smoke-acp-session-reuse-live` reads those notices as its reuse oracle and treats recall only as supporting evidence (`scripts/smoke-acp-session-reuse-live.ts`); it does not independently certify the backend's own native session.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
## 2. Manual judgement checks — what the gates cannot fully judge
|
|
280
|
+
|
|
281
|
+
The invariants a gate certifies are listed in Part II ("Gate pointers for the live-session invariants"). A gate certifies its fixture contract, not this session. What follows is what a gate cannot fully judge.
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
### 2.1 MCP callable-identifier shape (verified property, gate-external)
|
|
285
|
+
|
|
286
|
+
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):
|
|
287
|
+
|
|
288
|
+
| Backend | Literal identifier | Boundary |
|
|
289
|
+
|---|---|---|
|
|
290
|
+
| Claude | `mcp__entwurf-bridge__entwurf_v2` | native Claude tool surface + explicit MCP server |
|
|
291
|
+
|
|
292
|
+
Cortex ACP is disabled; its older callable-identifier observations are historical.
|
|
293
|
+
|
|
294
|
+
### 2.2 MCP injection visibility
|
|
295
|
+
|
|
296
|
+
Folded into §1A.1 Layer 2 and §1B.3 item 3.
|
|
297
|
+
|
|
298
|
+
### 2.3 Process / cache hygiene — the orphan bound (§gate-external judgement)
|
|
299
|
+
|
|
300
|
+
Apply per backend under test:
|
|
301
|
+
|
|
302
|
+
```
|
|
303
|
+
AFTER_<BACKEND> ≤ BEFORE_<BACKEND> + (distinct alive
|
|
304
|
+
(sessionKey, backend, modelId, bridgeConfigSignature) tuples this run holds open)
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
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.
|
|
308
|
+
|
|
309
|
+
### 2.4 pi session record as a shared memory axis
|
|
310
|
+
|
|
311
|
+
Pi session files stay the shared record source even under ACP: "Claude via ACP, memory via the pi axis (JSONL → Denote/andenken)", and the AI does not run its own memory layer. The check and its recipe are §1B.8.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
# Part II — Maintainer floor (read for context; the subject does not run it)
|
|
316
|
+
|
|
43
317
|
## 0A. Execution Policy — Transparent Mode
|
|
44
318
|
|
|
45
319
|
Verification here is not a benchmark. In production we exchange short turns and stop immediately to isolate a cause before resuming when something looks off. This document records **verification intent (what we look at) and pass criteria (how to judge)**; the execution shape is the agent's choice as long as the criteria are met.
|
|
@@ -92,6 +366,27 @@ Migration moves lines BETWEEN the two axes `inventory-verification-surface.ts` c
|
|
|
92
366
|
drop in the COMBINED number is subtraction. That is why the inventory reads both locations: a gate
|
|
93
367
|
that moved out of `scripts/` and into a file beside its subject would otherwise read as deleted.
|
|
94
368
|
|
|
369
|
+
### Gate pointers for the live-session invariants
|
|
370
|
+
|
|
371
|
+
The single-turn / multi-turn / cross-process / persistence-boundary / shutdown invariants that earlier editions hand-ran against the retired v1 verbs are now **deterministic or live gates**. Verify them through the gate, and reserve manual time for the human-judgement surfaces below.
|
|
372
|
+
|
|
373
|
+
| Invariant | Current gate (pointer) |
|
|
374
|
+
|---|---|
|
|
375
|
+
| Single-turn prompt extraction, SessionStart hook not mistaken for prompt | `smoke-acp-raw-turn-live` (a bare-vendor shape by design: no overlay and no session meta, so it is not the production session shape), `check-acp-prompt-builder` |
|
|
376
|
+
| Multi-turn continuity + recall (process-scoped reuse) | `smoke-acp-session-reuse-live`, `check-acp-session-reuse` |
|
|
377
|
+
| Cross-process continuity / cache before-after | `check-acp-session-store` (signature, decideBootstrap, persist/parse) |
|
|
378
|
+
| 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` |
|
|
379
|
+
| Tool-call / event mapping | `check-acp-event-mapper`, `smoke-acp-provider-live` |
|
|
380
|
+
| 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` |
|
|
381
|
+
| Claude typed `incomplete_tool_call` prompt failure — real pi retry/overflow classifiers reject the fixed verdict, raw evidence stays in existing diagnostics, exactly one seal and drop on new/reuse; other failures retain the legacy stderr path, cancel stays separate. A deterministic receipt does not certify the target vendor runtime. No LIVE gate induces this rejection; the raw-turn and reuse smokes certify only their own rows above. | `check-acp-vendor-rejection` (four mutants) |
|
|
382
|
+
| Claude set-model answer read back before the prompt — an exact row, or the one alias row (value and name) measured for the requested id; a missing model option, another row or any other value/name pair refuses with non-transient text. Deterministic only: the answer shapes measured at 0.85.1, and unchanged at 0.90.0 with the production session meta (no prompt), are fixture literals, not a runtime certificate. | `check-acp-set-model-readback` (two set-model mutants), `check-probe-ordering` |
|
|
383
|
+
| Claude effort (#142) — curated rows offer pi's `low..max` through pi's own selector and clamp; the level is resolved before any spawn and set + read back as `effort` after set-model on a new session, and on reuse only when it changed (not in the reuse signature); no level, an unsupported level or a non-effort value refuses as `acp-thinking-level-unsupported`; a refused or mismatched answer fails before the prompt, our authored text non-transient (the appended stderr tail and a bootstrap timeout follow the existing pre-prompt path), and a reused session is dropped, so the next turn opens a new session and resends the transcript. Deterministic only: the effort shapes measured at 0.106.0 with no prompt are fixture literals; readback is not evidence of applied reasoning depth or speed. | `check-acp-set-model-readback` (five effort mutants) |
|
|
384
|
+
| What an abort leaves (#142) — after the turn settles, a reused turn the agent closed on `session/cancel` says the live session continues; a dropped session (cancelled first turn, escalation, pre-prompt abort) says the next message opens a new one; both say changes already made stay. A rebuilt (new-session) transcript follows an `aborted` assistant turn with one status line saying the turn was cut and a cut is not rollback, claiming nothing about what ran; the reuse delta carries no such line. An abort already raised, or arriving, while a reuse turn awaits a changed effort's answer settles on the abort, sends no prompt and drops the session. A reuse turn's stream opens only when its own prompt is sent, so an update arriving during its effort set is never shown or sealed as that turn's; inside the prompt window the wire carries no turn id and that part rests on the adapter. Deterministic only (scripted ACP partner and pure transcript rendering); the real-vendor n=1 cells are in #142, not a release certificate. | `check-acp-set-model-readback` (seven cancel mutants) |
|
|
385
|
+
| Pi's summary request (#163) — `/compact`, the threshold, overflow recovery and `/tree` summaries are admitted only on an empty tool surface WITH `cacheRetention: "none"` (an ordinary all-tools-excluded turn still refuses); the turn runs on a new, never-retained child with no tools, MCP servers, plugins, pre-approvals or setting sources, sends Pi's summarization instructions as the first prompt block and no augment, and emits no notice, so the stored summary is exactly the model's text; a `cancelled` stop Pi did not abort is sealed as an error, so Pi never keeps that partial text; `session_compact` closes the session's retained child unless its turn is in flight. Deterministic only: Pi's real `generateSummary` / `generateBranchSummary` drive the turn against a scripted ACP partner; the live `/compact` cell is in #163. | `check-acp-set-model-readback` (ten summary/compaction mutants), `check-acp-provider-surface` |
|
|
386
|
+
| Tool visibility (#163) — a title-only update names the running call on one display-only line (a beat in the same update prints alone, a repeated title prints nothing); a finished call previews at most 5 lines / 400 bytes of its output, head on success and tail on failure, nothing when the one-line summary already holds it, hidden with the tool stream, each line keeping its indentation; every notice and preview line is cleaned as Pi cleans tool output (ANSI/OSC sequences and C0 controls removed, compared against Pi's installed `stripAnsi`/`sanitizeBinaryOutput`), plus DEL and C1; the backend's own compaction shows trigger, tokens before and after, duration and failure on one lifecycle line, once. All three are signed, so they stay out of replay, the reuse signature and andenken `control-v1` embedding. Deterministic only: frames follow claude-agent-acp 0.107.0 as read, not a live capture. | `check-acp-set-model-readback` (thirteen mapper mutants) |
|
|
387
|
+
| Operator mcpServers / skills reach the live session | `smoke-acp-mcp-live`, `smoke-acp-skill-live`, `check-acp-config` |
|
|
388
|
+
| Overlay isolation + memory containment | `check-acp-overlay`, `smoke-acp-memory-containment-live`, `check-acp-tool-surface` |
|
|
389
|
+
|
|
95
390
|
### The canonical floor — two entry points
|
|
96
391
|
|
|
97
392
|
- **Deterministic floor — two tiers (#70):** `pnpm check` is the everyday CORE — toolchain (lint + typecheck), the vitest lanes, and the pure-unit / behavioral-contract / source-topology gates plus the cheap static coherence checks. It prints its own total wall time; acceptance is ≤60s on the reference host `oracle` (an operator measurement, never a hard wall-clock gate on arbitrary hosts). `pnpm run check:full` is the FULL deterministic floor — the core plus the hermetic-integration and package/install tiers — and is what the frozen-candidate protocol, push CI, release-gate, and `prepublishOnly` run. Exact membership is the named `check:*` group scripts in `package.json` (the executable SSOT — this document records meaning and principles, not the command list); a gate changes tier by semantic-class decision, never by getting faster or slower. One core member assumes a build output: the beside test `pi-extensions/entwurf-control.test.ts` (reached through `check-tests-beside-behavior`) registers the COMPILED bridge and refuses by name when it is absent. `prepare` normally builds it at install; after an `--ignore-scripts` install or a bridge source change, run `pnpm run build-bridge` (in the sandbox candidate when verifying one) before the core. The FULL tier carries the qualification HEAD (`check-gate-manifests`, through `check:hermetic`); the everyday core does not, and neither tier carries the separately scheduled mutant-executing body (`check-gate-qualification`).
|
|
@@ -101,21 +396,21 @@ that moved out of `scripts/` and into a file beside its subject would otherwise
|
|
|
101
396
|
- **MUST tier** (release-blocking — owns the exit code; "green" applies only here): `pnpm run check:full`, `smoke-entwurf-v2-matrix-live`, `check-bridge`, `doctor-pi-provider` (#81 — `check-bridge` proves the launcher this checkout SHIPS; this proves the invocation the operator's pi provider actually EXECS, by booting it and requiring the entwurf verb set back, because `command -v` answers yes for a command that exits 127; wired as a step on 2026-08-19 after a relocated pnpm cmd-shim cost a cut sixteen LIVE steps before the same fact surfaced at `smoke-acp-bundled-mcp-live`), the resident-garden-guard zero-token half (record birth / record-keyed socket / attach-on-reopen), the `smoke-acp-*-live` ACP plugin smokes (socket-citizen / raw-turn / overlay / provider / session-reuse / carrier-augment / memory-containment / rgg / mcp / skill / bundled-mcp / v2-send), the axis wired in on 2026-07-31 that the aggregate had simply never listed (`smoke-claude-native-resume-live`), `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 — the integrated `smoke-mux-lifecycle-live` (its own note below), and the two OMP steps 0.16.0 wired: `smoke-omp-receive-live` (the addressed roundtrip into a live omp citizen; it reads the capability registry and decides its own outcome rather than passing by default) and `smoke-omp-fresh-live` (the clause 7 receipt the release stop now requires). (`smoke-session-id-name` is gone — #50 C3: its `--session-id`/`--name` substrate has no entwurf consumer anymore.)
|
|
102
397
|
- **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`).
|
|
103
398
|
- **Every MUST step is invoked and reports its own outcome.** Prerequisite-bearing LIVE MUST steps ride the P1 STEP OUTCOME protocol (`scripts/lib/step-outcome.sh`): exit 0 = PASS, exit 97 = SKIP (a prerequisite the step does not have, printed as an `[entwurf:skip]` line), anything else = FAIL. The non-skippable static step (`pnpm run check:full`) is inline: 0 = PASS, nonzero = FAIL, no SKIP arm — it has no prerequisite to decline. A skip is never counted as a pass — that hole is what let a cortex-less host read as cortex acceptance. Without `--cut` this is the unattended diagnostic: SKIPs are reported and the run still exits 0. **`--cut` makes it acceptance and any MUST SKIP is red**, which is how "a real cut needs `LIVE=1` with `SKIP=0`" stopped being prose. A green MUST gate is **necessary, not sufficient** — GLG authorizes the cut.
|
|
104
|
-
- **When cost-bearing MUST gates run (
|
|
399
|
+
- **When cost-bearing MUST gates run (the F6/F7 lesson, 2026-07-23; timing since 2026-09-11 owned by AGENTS.md Scheduling):** a MUST-tier live gate covering a touched rail runs, and must be green, before that change lands. It is never left unrun because a human approved the change: deferring a wired gate to a human decision is what let F6/F7 ship reviewed-and-approved, and the wiring exists so the verdict never depends on who pressed enter. Where in the sequence it runs is AGENTS.md's call: interim checkpoint commits carry scoped review and focused checks with unmeasured boundaries recorded, and native/LIVE/release floors are mandatory before landing. LIVE is opt-in (AGENTS.md Verification): a model-bearing run needs the operator's go for that spend. Without it the gate stays unrun and the change does not land; a missing go blocks landing and never stands in for the gate. The 2026-07-23 wording, "before cross-review is requested", predates that sequence. "배선이 없어 못 한 것은 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.
|
|
105
400
|
|
|
106
401
|
> **The herdr rail is an on-demand axis until it has run.** `smoke-herdr-fresh-call-live` opens a real caller inside a real herdr pane, has it invoke the PUBLIC `entwurf_fresh_call`, and reads the child's nonce callback — the one axis no deterministic gate reaches, since the rail is selected from the caller's own process environment. **The release aggregate does not yet require the herdr rail**: herdr is optional (a cut on a host without it must not block), and first evidence precedes promotion — a rail whose first acceptance run is days old has not earned a place in the gate that blocks every cut. Run it directly with `LIVE=1 ./run.sh smoke-herdr-fresh-call-live` whenever a cut changes herdr rail code, and promote it to a MUST only after the axis has a run history to point at. Without `LIVE=1`, or without herdr/pi/claude on PATH, it reports protocol SKIP — never a pass.
|
|
107
402
|
|
|
108
|
-
> **The plugin's FIRST USER PATH is its own on-demand axis, and an npm acquisition receipt holds only for the ref it ran on (#118 홉 1).** Every other herdr gate proves the plugin against a source this repository controls: `check-herdr-plugin-build` drives a stub, and `smoke-herdr-plugin-build-live` redirects the product remote to a local bare clone with git `insteadOf` and asserts `identity.kind === "herdr-checkout"`.
|
|
403
|
+
> **The plugin's FIRST USER PATH is its own on-demand axis, and an npm acquisition receipt holds only for the ref it ran on (#118 홉 1).** Every other herdr gate proves the plugin against a source this repository controls: `check-herdr-plugin-build` drives a stub, and `smoke-herdr-plugin-build-live` redirects the product remote to a local bare clone with git `insteadOf` and asserts `identity.kind === "herdr-checkout"`. `LIVE=1 ./run.sh smoke-herdr-raw-install-live [--ref <REF>]` fills that row in a clean `node:24` container with no socket, config, cache or repo mounted, no `insteadOf`, the public remote spelled as a user would type it, and pi / herdr / Claude Code installed in the IMAGE BUILD as scaffolding (Hard Rule 17 — the product face begins at `herdr integration install pi`). herdr itself comes from `scripts/install-herdr-ci.sh` against `scripts/fixtures/herdr-supply.json`, so no version or digest lives here. Like the other two herdr LIVE lanes it is **on-demand and not an aggregate MUST** — herdr is optional, a cut on a host without it must not block, and first evidence precedes promotion. Without `LIVE=1`, or without a usable Docker daemon, it reports a named SKIP; `ENTWURF_REQUIRE_DOCKER=1` turns the Docker absence red. Neither skip is a pass. Pin history, the `--ref` and first-question notes and the cell-by-cell account are in [docs/baseline-receipts.md](./docs/baseline-receipts.md) (read on GitHub) and in the smoke's own header.
|
|
109
404
|
|
|
110
405
|
> **The Herdr plugin's install-time build has two axes, and one of them needs the network (#116 M3-b3).** `check-herdr-plugin-build` is deterministic and rides `check:hermetic`: the listing reaches the runner through its own spawn seam (there is no fake `herdr` binary in this repo), and the one cell that drives the REAL binary reports a named SKIP on a host without it — `ENTWURF_REQUIRE_HERDR=1` makes that absence red. What it cannot have is the real acquisition: `npm pack git+https://github.com/junghan0611/entwurf.git#<full sha>` builds the bridge through `prepare`, which installs devDependencies from the registry. So `LIVE=1 ./run.sh smoke-herdr-plugin-build-live` owns that axis, and its cells are **two kinds of evidence, labelled as such**: three are the real Herdr journey — a real `herdr plugin install` driving the real `[[build]]`, with the UNCHANGED product remote redirected to a local bare clone by git `insteadOf` (the one substitution, which is what makes an unpushed candidate testable) — covering remote-commit available, the `{pi}` → `{pi, claude-code}` reinstall with OpenCode as a zero-write negative control and exactly ONE counted vendor MCP owner entry, and the post-build Herdr-commit gap (where the ledger has already rebound to the gap commit, so the honest assertion is that transition and not unchanged bytes). The fourth cell — remote-commit **unavailable** — calls the shipped runtime leaf directly with the fixed product argv and is therefore **acquisition-leaf evidence, not a journey**; routing it through Herdr would add a second explanation for one red. Its oracle is the honest one too: active runtime, ledger and harness bytes preserved, while the journal is left as the certified `installing` retry authority the transaction deliberately writes before acquiring, and a normal install afterwards is green. Its Claude cell is where the vendor question the deterministic gates refuse to claim gets answered — whether Claude Code accepts an ABSOLUTE executable as an MCP command — and it reports a named skip on a host without `claude`, never a pass. Like the herdr fresh-call rail, this smoke is **on-demand and not an aggregate MUST**. The release aggregate does not require the plugin build smoke: herdr is optional, a cut on a host without it must not block, and first evidence precedes promotion.
|
|
111
406
|
|
|
112
407
|
> **Switching the plugin's production acquisition source is a re-proof, not a configuration change (#116 M3-b3).** `runtime-lock.json` carries a closed `source` discriminant: `npm` (exact `name@version` plus the published sha512, compared against the tarball's own bytes) is the production authority, and `herdr-checkout` (the exact commit Herdr checked out, from the fixed remote) is a VERIFICATION-ONLY carrier that exists so a candidate needs no npm release. Evidence does not transfer between them. Before a release that moves the production source — to npm, or to a GitHub Release tarball plus its sha512 — the exact acquisition and integrity comparison, the installed runtime (name@version, compiled entry, three executable bins, a real `check-bridge`), the swap and torn-swap recovery, activation and deactivation, and the package-consumer proof must all be re-run against THAT source. A candidate proof green on the checkout carrier says nothing about a registry artifact, and the reverse is equally true. **Records from before this contract are refused, not migrated:** a v1 runtime journal or activation ledger fails certification by name, and the way forward on such a host is an explicit `entwurf herdr-plugin-deactivate` (or a hand-cleared runtime/ledger state) before the next install — there is no reader that accepts both schemas, because the older shape cannot say WHICH artifact it was.
|
|
113
408
|
|
|
114
|
-
> **Cortex is
|
|
409
|
+
> **Cortex ACP is disabled.** Retired Cortex model ids are not registered; Entwurf fresh/resume exact admission refuses them, and the ACP adapter refuses a Cortex id that reaches it before starting a child, without a Claude fallback. Pi's own direct `--model` fuzzy selection happens before the adapter; the result for a typed retired id has not been measured here. The former Cortex direct LIVE smoke now refuses by name rather than probing a vendor. Past Cortex receipts remain historical evidence, not proof of this disabled admission. The Claude and native-citizen LIVE floors, including Codex and mux, are unchanged.
|
|
115
410
|
>
|
|
116
411
|
> 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`.
|
|
117
412
|
>
|
|
118
|
-
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way. The native pi launch names `placement.tmuxSession` (#108): the harness asks tmux itself that the pane sits in a caller-distinct seat session on the same private server, that the caller's windows are unchanged, and that the close later removes only that window and leaves the seat's anchor standing. The steps are: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-6.1-sol:low` and recorded-ACP `entwurf/claude-sonnet-5-5`, the only shape that re-injects a bridge extension), and the Claude Code cell, whose sibling is still live at that point, has its resume refused as `target-live` with no window opened and no lock residue (the per-gid coordination lock is released). Claude Code's dormant same-id resume (#147 L2) is certified deterministically; its LIVE dormant→resume leg is not in this MUST yet. One test-owned retire→resume round trip outside this gate is recorded as dated n=1 evidence in [BASELINE](./
|
|
413
|
+
> **The integrated mux lifecycle IS a release-gate MUST.** `LIVE=1 ./run.sh smoke-mux-lifecycle-live` enters through a real MCP `tools/call` on the shipped bridge launcher and follows one citizen the whole way. The native pi launch names `placement.tmuxSession` (#108): the harness asks tmux itself that the pane sits in a caller-distinct seat session on the same private server, that the caller's windows are unchanged, and that the close later removes only that window and leaves the seat's anchor standing. The steps are: fresh-call launch receipt, the sibling's own nonce callback whose SENDER ENVELOPE is the address, an `entwurf_v2` control-socket send that lands in the sibling's own transcript, `entwurf_resume_call` REFUSED while that citizen is live, a stable-handle close proving pane and socket gone with the record preserved, delivery to the dormant citizen refused honestly, then the public `entwurf_resume_call` — whose LAUNCH and OBSERVATION receipts stay apart — and finally an `entwurf_v2` send the resumed session answers with a fact it was told BEFORE the window closed. That last step is the point: a socket answering under the same garden id proves a process stood up at that address, and only the recall proves the same conversation came back. Both pi provider shapes are driven to it (native `openai-codex/gpt-6.1-sol:low` and recorded-ACP `entwurf/claude-sonnet-5-5`, the only shape that re-injects a bridge extension), and the Claude Code cell, whose sibling is still live at that point, has its resume refused as `target-live` with no window opened and no lock residue (the per-gid coordination lock is released). Claude Code's dormant same-id resume (#147 L2) is certified deterministically; its LIVE dormant→resume leg is not in this MUST yet. One test-owned retire→resume round trip outside this gate is recorded as dated n=1 evidence in [BASELINE](./docs/baseline-receipts.md#147-native-round-trip-2026-10-22-n1); it is not this MUST.
|
|
119
414
|
>
|
|
120
415
|
> One cell cannot be fully fenced, and that is recorded rather than glossed: the recorded-ACP pi cell runs under the operator's REAL home, because its provider spawns `claude` as a child that authenticates from there — measured, a fenced HOME kills that turn with `Authentication required` before the model is ever reached, and `CLAUDE_CONFIG_DIR` alone does not fix it. That is the same trade `smoke-acp-bundled-mcp-live` already makes. While that cell runs, its citizen's control socket and per-gid lock exist under the operator's own `~/.pi/entwurf-control` and `~/.pi/entwurf-v2-locks`; its meta store stays fixture, so no garden record is minted outside the fixture, and the run ends by proving all six real roots hold the entry sets they started with, with no fixture garden id and no leftover lock.
|
|
121
416
|
>
|
|
@@ -352,36 +647,16 @@ every focused gate green at the time:
|
|
|
352
647
|
stale". The installed surfaces run compiled JS (Hard Rule 11), so an un-rebuilt `dist` means the
|
|
353
648
|
focused gates proved the source while every package-shaped gate still judged the previous build.
|
|
354
649
|
|
|
355
|
-
### Wording — avoid safety-interpretation contamination
|
|
356
|
-
|
|
357
|
-
When injecting a fact for a continuity check, use **plaintext that does not trigger model safety interpretation**. Avoid `secret token`, `password`, `API key`, `credential`, and meta-directives like "do not leak" — such wording makes the model treat the prompt as an exfiltration attempt and refuse, which makes **continuity look broken even when it is alive** (this happened once with `test-token-123`, misdiagnosed as a delegation failure). Instead: `The code word is owl → reply in one word → owl`; code names / colors / animal names. Do not mix continuity and safety-behavior verification in one prompt.
|
|
358
|
-
|
|
359
|
-
### bridge continuity vs semantic continuity
|
|
360
|
-
|
|
361
|
-
- **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.
|
|
362
|
-
- **semantic continuity:** a fact from a prior turn is retrievable in a later turn.
|
|
363
|
-
|
|
364
|
-
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 read the turn's own lifecycle notices in the assistant text (`[acp: preparing …]` on a new session, `[acp: reusing live session]` on reuse). No automated smoke separates these yet.
|
|
365
|
-
|
|
366
|
-
## 0. Quality Criteria
|
|
367
|
-
|
|
368
|
-
The goal is not merely "invoke Claude Code." We want:
|
|
369
|
-
|
|
370
|
-
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.
|
|
371
|
-
2. **Preservation of pi harness semantics** — pi session files / transcripts / memory pipeline stay a shared axis.
|
|
372
|
-
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.
|
|
373
|
-
4. **Thin bridge** — no second harness built inside this repo.
|
|
374
|
-
5. **Explicit capability boundary** — pi custom tool / user MCP visibility is determined solely by `entwurfProvider.mcpServers`; no automatic `~/.mcp.json` loading.
|
|
375
|
-
6. **Operational hygiene** — no orphan subprocesses, no excess persisted session garbage.
|
|
376
|
-
|
|
377
650
|
---
|
|
378
651
|
|
|
379
652
|
## 1. Setup
|
|
380
653
|
|
|
381
|
-
**
|
|
654
|
+
> **An agent session never runs this section.** Install, re-install, takeover and uninstall rewrite operator-owned registration, so they are an operator action in a human shutdown window. On a host whose user scope another root already owns, a re-run `setup` is a zero-write refusal, not a repair; the owner-specific path, including `takeover-user-scope` and a Herdr developer checkout, is [setup-clean-host §1.1](./docs/setup-clean-host.md#11-user-scope-ownership-one-shared-registration-one-recorded-owner). An agent verifying an installed host reads doctors (§1B.2) and stops at "this looks broken", reporting instead of repairing.
|
|
655
|
+
|
|
656
|
+
**One install command to remember: `./run.sh setup <project>`.** It is idempotent: on a host whose registration this checkout owns, the operator re-runs the exact same command when something looks wrong. There is no second install surface to juggle: from a clone `setup` runs the whole floor in order.
|
|
382
657
|
|
|
383
658
|
1. `pnpm install` — installs the pinned development dependencies and builds the bridge (source-checkout bootstrap only; an installed package never runs npm/pnpm inside `node_modules`)
|
|
384
|
-
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.5.
|
|
659
|
+
2. pi wiring → `<project>/.pi/settings.json` + user-scope registration — only when a `pi` inside the supported range (`>=1.5.2 <1.6`) is on PATH; absent pi is an explicit zero-state SKIP, a below-floor pi is a detected FAIL. The user-scope entry is owner-recorded (#86 C2): another root's live-or-missing ownership makes this step a zero-write refusal (setup: pi FAIL) that names `takeover-user-scope`; the install-states bind the exact managed settings path (a drifted/symlinked/corrupt target is a zero-write refusal) and the inverse removes only the recorded owner's exact entry; `doctor-pi-package` reports the verdict
|
|
385
660
|
3. Claude meta-bridge global plugin — only when `claude` is on PATH; otherwise skipped cleanly
|
|
386
661
|
4. source stable-bin exposure — including certified `entwurf` → this checkout's `run.sh`, the managed runtime Copilot fresh resolves; helper units are attempted independently and a foreign helper is a named FAIL
|
|
387
662
|
5. agy bridge + exact permission + statusline + `PreInvocation` hook — only when `agy` is on PATH; each adapter is idempotent and independently doctorable
|
|
@@ -393,7 +668,7 @@ The goal is not merely "invoke Claude Code." We want:
|
|
|
393
668
|
```bash
|
|
394
669
|
git clone https://github.com/junghan0611/entwurf /path/to/entwurf && cd $_
|
|
395
670
|
./run.sh setup /path/to/consumer-project
|
|
396
|
-
# re-run the SAME command
|
|
671
|
+
# the owner of this registration may re-run the SAME command to repair it (§1 note above)
|
|
397
672
|
```
|
|
398
673
|
|
|
399
674
|
Expected tail on a fully green host: `DONE: entwurf setup — result: green (computed from the component outcomes above).` The summary above it lists every component as PASS/SKIP/FAIL; a detected harness that could not be completed is named FAIL and the command exits nonzero (`result: NON-GREEN (FAIL: …)`) while every valid component stays installed — re-running the same `setup` is the repair action. On a host with `claude`, verify `./run.sh doctor-meta-bridge`. On a host with `agy`, verify all three: `doctor-agy-bridge`, `doctor-agy-statusline`, and `doctor-agy-hooks`. After adding a backend to `META_BACKENDS`, re-run the sibling install then the doctor — a green checkout with a stale deployed plugin is a silent write-stop on that rail. Each harness doctor remains the fail-loud per-leaf acceptance surface.
|
|
@@ -450,95 +725,7 @@ mailbox with `origin=pi-session`, `replyable=true`).
|
|
|
450
725
|
|
|
451
726
|
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 pi citizen reaches the compiled `entwurf-bridge` through Pi's built-in MCP (`mcp__entwurf_bridge__<verb>`, seven active tools and two hidden in the 0.41.0 source; installed/live offering requires its own receipt), while the ACP backend reaches that bridge through the explicit `entwurfProvider.mcpServers` projection in its own callable dialect (see §2.1). Compare the actual ingress provenance and backend-native tools, not an assumed absence of MCP on pi; receive to the pi citizen remains its record-addressed control address (a Unix socket; a named pipe on the experimental native-Windows Pi preview). Honest "I cannot tell" hedging is preferable to inventing provenance. This is the current #125 comparison criterion, not a newly measured parity receipt. agy is graded by its native-citizen checklist, not by pretending it has an ACP overlay.
|
|
452
727
|
|
|
453
|
-
|
|
454
|
-
while keeping cortex's own native tool surface. Its callable MCP identifier shape is
|
|
455
|
-
the same as Claude's, but it has no system-prompt carrier: engraving is prepended to
|
|
456
|
-
the first user augment. Installed-model enumeration is deterministic; candidate-installed
|
|
457
|
-
LIVE Cortex acceptance and its remaining host limits are recorded per cut rather than
|
|
458
|
-
frozen here.
|
|
459
|
-
|
|
460
|
-
---
|
|
461
|
-
|
|
462
|
-
## 1A. Main Agent Evaluation — Is `entwurf` Claude strong enough?
|
|
463
|
-
|
|
464
|
-
Separate from continuity gates. Gates prove "sessions continue"; this questionnaire examines tool self-awareness / native tool usability / MCP-boundary awareness / long-turn focus / quality vs direct Claude Code. Run it against `entwurf/claude-sonnet-5-5` via a direct `pi --provider entwurf` turn (or a live ACP session); accumulate turns by re-prompting the same target.
|
|
465
|
-
|
|
466
|
-
### 1A.0 Two carrier surfaces — engraving vs pi-context-augment (load-bearing)
|
|
467
|
-
|
|
468
|
-
`entwurf` delivers identity-relevant text through **two structurally distinct surfaces**. Collapsing them into "the system prompt" is the most common verifier-side mistake. (BASELINE Q-B0/Q-L1 grade the same separation operator-side.)
|
|
469
|
-
|
|
470
|
-
| Surface | Source | Delivery shape | Default content |
|
|
471
|
-
|---|---|---|---|
|
|
472
|
-
| **Engraving carrier** | `pi-extensions/lib/acp/prompts/engraving.md` (or `ENTWURF_ACP_ENGRAVING_PATH`) | Claude `_meta.systemPrompt` — full-replacement identity slot | Operator-authored, optional opt-out; tiny non-empty by default on Claude ACP (replaces the `claude_code` preset + strips its auto-memory advertisement). Emptying the file is the opt-out. |
|
|
473
|
-
| **pi-context-augment** | `pi-extensions/lib/acp/augment.ts` (`enrichTaskWithProjectContext`) | First-user-message prepend (not the system slot) | Always populated on ACP-routed targets: (1) the bridge identity line, (2) `~/AGENTS.md` body, (3) the cwd repo's `AGENTS.md` in a `<project-context path="…">` block. |
|
|
474
|
-
|
|
475
|
-
Pass (carrier honesty): the subject distinguishes engraving from pi-context-augment by name or structure without prompting; on ACP targets confirms all three augment components arrived; may quote the engraving but must **not** attribute bridge identity / AGENTS / memory policy to it. Fail: attributes the bridge-identity narrative to the engraving carrier; claims the augment is empty on an ACP run; invents engraving content. Native pi exception: on native targets the bridge-identity line and `~/AGENTS.md` are not part of the augment — the PASS criterion is honesty about what arrived, not the three-component checklist.
|
|
476
|
-
|
|
477
|
-
### 1A.1 Layers
|
|
478
|
-
|
|
479
|
-
- **Layer 0 — self-awareness:** ask environment self-awareness / MCP visibility / upstream-instruction awareness, guessing prohibited. Pass: recognizes native tool family, says "I don't know" honestly, answers MCP visibility only as configured, describes upstream instruction type without reproducing internal prompts. Fail: claims a nonexistent tool, conflates pi-custom and native tools, hallucinates MCP visibility, or conflates the two carriers (§1A.0).
|
|
480
|
-
- **Layer 1 — native tool use:** throw file-reading / structure-analysis / regression-hunting tasks. Pass: Read/Edit/Bash/Grep/Glob selection is natural; no detour through MCP or recursive `pi`. Fail: strange detours for simple reads; speaks from memory without reading.
|
|
481
|
-
- **Layer 2 — MCP boundary:** by default the entwurf MCP tools are not visible (they appear only when `entwurf-bridge` is registered). Pass: says invisible tools are not visible; explains the native-vs-MCP boundary; treats `entwurf_register_native` as binding an already-running conversation, never as fresh spawn. Fail: pretends to use an unseen tool; mimics entwurf via recursive `pi`.
|
|
482
|
-
- **Layer 3 — focus across turns:** inject a fact, then accumulate turns mixing retrieval/exploration. Pass (post-0.4.1): after **8 turns** holds **3+ early facts** incl. **one verbatim string injected before turn 5**; no repeated exploration, no self-contradiction, no tool-strategy drift. Fail: forgets early reads; paraphrases instead of returning the verbatim string. Note: entwurf exposes no user-facing compaction; use the backend's `usage_update` footer as an overflow-risk signal (it follows the ACP backend's `used/size`, not pi's visible-transcript estimate).
|
|
483
|
-
- **Layer 4 — vs direct Claude Code:** requires a verifier holding **both** the `entwurf` and a direct path (human-in-loop, or both transport handles). Compare latency / native tool accuracy / detours / boundary confusion / quality around turns 10–15. Repeated tool confusion, long-turn forgetting, or boundary workarounds are a fail.
|
|
484
|
-
|
|
485
|
-
Interpretation: Layers 0–2 healthy → basic qualifications confirmed. Layer 3 weak → strengthen prompt shape + corroborate with bootstrap logs / process state / sentinel recall. Layer 4 much weaker than direct → revisit bridge handoff. This questionnaire does not replace gates.
|
|
486
|
-
|
|
487
|
-
---
|
|
488
|
-
|
|
489
|
-
## 2. Manual judgement checks — what the gates cannot fully judge
|
|
490
|
-
|
|
491
|
-
The single-turn / multi-turn / cross-process / persistence-boundary / shutdown invariants that earlier editions hand-ran against the retired v1 verbs are now **deterministic or live gates**. Verify them through the gate, and reserve manual time for the human-judgement surfaces below.
|
|
492
|
-
|
|
493
|
-
| Invariant | Current gate (pointer) |
|
|
494
|
-
|---|---|
|
|
495
|
-
| Single-turn prompt extraction, SessionStart hook not mistaken for prompt | `smoke-acp-raw-turn-live` (a bare-vendor shape by design: no overlay and no session meta, so it is not the production session shape), `check-acp-prompt-builder` |
|
|
496
|
-
| Multi-turn continuity + recall (process-scoped reuse) | `smoke-acp-session-reuse-live`, `check-acp-session-reuse` |
|
|
497
|
-
| Cross-process continuity / cache before-after | `check-acp-session-store` (signature, decideBootstrap, persist/parse) |
|
|
498
|
-
| 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` |
|
|
499
|
-
| Tool-call / event mapping | `check-acp-event-mapper`, `smoke-acp-provider-live` |
|
|
500
|
-
| 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` |
|
|
501
|
-
| Claude typed `incomplete_tool_call` prompt failure — real pi retry/overflow classifiers reject the fixed verdict, raw evidence stays in existing diagnostics, exactly one seal and drop on new/reuse; other failures retain the legacy stderr path, cancel stays separate. A deterministic receipt does not certify the target vendor runtime. No LIVE gate induces this rejection; the raw-turn and reuse smokes certify only their own rows above. | `check-acp-vendor-rejection` (four mutants) |
|
|
502
|
-
| Claude set-model answer read back before the prompt — an exact row, or the one alias row (value and name) measured for the requested id; a missing model option, another row or any other value/name pair refuses with non-transient text. Deterministic only: the answer shapes measured at 0.85.1, and unchanged at 0.90.0 with the production session meta (no prompt), are fixture literals, not a runtime certificate. | `check-acp-set-model-readback` (two mutants), `check-probe-ordering` |
|
|
503
|
-
| Operator mcpServers / skills reach the live session | `smoke-acp-mcp-live`, `smoke-acp-skill-live`, `check-acp-config` |
|
|
504
|
-
| Overlay isolation + memory containment | `check-acp-overlay`, `smoke-acp-memory-containment-live`, `check-acp-tool-surface` |
|
|
505
|
-
|
|
506
|
-
### 2.1 MCP callable-identifier shape (verified property, gate-external)
|
|
507
|
-
|
|
508
|
-
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):
|
|
509
|
-
|
|
510
|
-
| Backend | Literal identifier | Boundary |
|
|
511
|
-
|---|---|---|
|
|
512
|
-
| Claude | `mcp__entwurf-bridge__entwurf_v2` | native Claude tool surface + explicit MCP server |
|
|
513
|
-
| Cortex | `mcp__entwurf-bridge__entwurf_v2` | same identifier shape, different native tool surface |
|
|
514
|
-
|
|
515
|
-
The identifier cannot distinguish Claude from Cortex; native tools and carrier facts must.
|
|
516
|
-
|
|
517
|
-
### 2.2 MCP injection visibility
|
|
518
|
-
|
|
519
|
-
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.
|
|
520
|
-
|
|
521
|
-
### 2.3 Process / cache hygiene — the orphan bound (§gate-external judgement)
|
|
522
|
-
|
|
523
|
-
Apply per backend under test:
|
|
524
|
-
|
|
525
|
-
```
|
|
526
|
-
AFTER_<BACKEND> ≤ BEFORE_<BACKEND> + (distinct alive
|
|
527
|
-
(sessionKey, backend, modelId, bridgeConfigSignature) tuples this run holds open)
|
|
528
|
-
```
|
|
529
|
-
|
|
530
|
-
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.
|
|
531
|
-
|
|
532
|
-
### 2.4 pi session record as a shared memory axis
|
|
533
|
-
|
|
534
|
-
The key invariant: **pi session files stay the shared record source even under ACP**. After a reuse pair finishes, locate the child pi session JSONL and confirm turns accumulated:
|
|
535
|
-
|
|
536
|
-
```bash
|
|
537
|
-
ls ~/.pi/agent/sessions/--*--/*_<SESSION_ID>.jsonl # path pattern, not a naive grep (which also hits the parent)
|
|
538
|
-
jq -r '.message.role // .type' "$F" | sort | uniq -c # role lives at .message.role
|
|
539
|
-
```
|
|
540
|
-
|
|
541
|
-
Pass: user/assistant turns accumulate normally; the transcript is not broken/empty because ACP was used. We preserve "Claude via ACP, memory via the pi axis (JSONL → Denote/andenken)" — the AI does not run its own memory layer.
|
|
728
|
+
Cortex ACP is disabled and is not a subject of this parity check.
|
|
542
729
|
|
|
543
730
|
---
|
|
544
731
|
|
|
@@ -550,7 +737,7 @@ The minimum passing bar:
|
|
|
550
737
|
2. **All four required CI jobs green on the exact release commit:** `check`, `install-surface`, the required Linux `artifact-consumer`, and `macos-install-surface` — promoted from non-voting to required in 0.20.0 (see the release acceptance axes table above for what its green run does and does not certify); preserve the Linux artifact-consumer's tarball digest and image identity. For a carrier-bearing release those CI tarballs are addon-less and are NOT the release candidate: the exact release bytes are the M3w-retrieved preview tarball, accepted separately by the eight Windows cells and the Linux container (axes row "Native-Windows carrier"). The four-job floor, macOS included, is unchanged. A macOS runner failure now blocks the cut like any other required job.
|
|
551
738
|
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.
|
|
552
739
|
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.
|
|
553
|
-
5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists `entwurf-bridge`
|
|
740
|
+
5. **Honest self-recognition:** the bridged model identifies its actual harness/backend, lists exactly the MCP servers its session schema carries — on the operator's default configuration that is `entwurf-bridge` — with the verbs its loaded bridge actually lists, counted from that schema (the standalone bridge lists nine; a native pi citizen offers seven with two hidden and the pi-durable contact eight, but those are other rails' counts and the ACP projection's own count is measured, not assumed), and presents a backend-native (not normalized) tool surface.
|
|
554
741
|
6. **Carrier separation honored:** engraving vs pi-context-augment kept distinct (§1A.0); no bridge-identity narrative attributed to the engraving carrier.
|
|
555
742
|
7. **agy native push paused (#152); acceptance is deterministic while the pause holds.** Required for a cut: a dispatch to an agy target returns `native-push-paused` with zero probe, send, adapter or record activity, an agy sender's `replyable` is false by name, and `entwurf_register_native` refuses before probing — proven by the deterministic `[QK:AGY-NATIVE-PUSH-PAUSED]` cell, which needs no agy conversation and is not a live round trip — and the agy record schema and reader stay in place, with the agy install and sender gates green inside `check:full`. A same-gid reply is not claimed while the pause holds. Not required for a cut: the retained legacy identity check (all three agy doctors, plus automatic birth/statusline/sender identity in a fresh conversation, where `agentId=meta-session/antigravity` is correct and model display is not part of it). It is an optional diagnostic run when explicitly asked, it is not send evidence, and a release does not claim that the installed agy host is certified or can receive. An optional diagnostic is not a cut requirement, and neither is a native-push PASS. Lifting the pause needs a separate future change with its own positive acceptance. Same-pid concurrent conversation invocation is not claimed.
|
|
556
743
|
8. **Codex caller-seat topology accepted:** its birth/MCP/status-line/terminal-title doctors are green and the on-demand real visible `Pi → Codex → Pi` cell records four coordinates: the operator-owned app-server in its own session A; initial Pi, omitted-placement fresh Codex, and Codex-opened outbound Pi all in a DIFFERENT session S; exact callbacks and addressed delivery succeed both ways. A ≠ S is a precondition, not a preference — the app-server's inherited environment names A, so an outbound Pi in S can only have come from the caller's own pane title, and the receipt must name `codex-title-anchor` as the rule that chose it. 0 or 2+ matching panes, and a caller whose `[tui].terminal_title` lacks `thread-id`, reject without mutation. Entwurf neither creates nor supervises the app-server, infers attached-TUI panes, nor claims placement beside a TUI whose thread nobody named. (The 2026-09-12 fixed-`codex`-home acceptance this condition replaced stays recorded in `DELIVERY.md` as history; #95 D1 retired that room.) Codex remains outside ACP and has no resume claim.
|
|
@@ -569,19 +756,22 @@ Passing establishes a **release verification floor**, not an 8-hour/day operatio
|
|
|
569
756
|
- **ACP turn evidence.** The ACP path writes no `[entwurf:*]` stderr markers, and `ENTWURF_CHILD_STDERR_LOG` is not an ACP observation surface (its mirror in `pi-extensions/lib/entwurf-core.ts` belongs to the retired child-pi spawn and has no caller). Read three things instead: the lifecycle notices the backend writes into the assistant text (`[acp: preparing …]` / `[acp: reusing live session]`), the turn's typed `stopReason` (an ACP `cancelled` ending maps to `aborted`, `pi-extensions/lib/acp/backend.ts:865-866`), and the identity (pid + starttime) of the launcher and of any process the turn started.
|
|
570
757
|
- **Retired dedicated smokes, live code invariants** (manual/troubleshooting only — *not* part of the release floor):
|
|
571
758
|
- *ACP-boundary model guard* — a session using the `entwurf` provider keeps its starting model: `pi-extensions/model-lock.ts` reverts set/cycle transitions touching that provider (native-to-native switching is free). This is an after-event revert, not a transcript-clean refusal. Separately, `session-store.ts` `SessionModelLockedError` refuses a persisted-record model mismatch at `decideBootstrap`. Gate: `check-model-lock` (core tier); the dedicated live `smoke-model-switch` was retired in v2. This is not a lifetime model pin on every garden citizen.
|
|
572
|
-
- *Cancel / abort cleanup* — an abort sends ACP `session/cancel` and lets the agent end its own turn (`awaitAcpPromptTurn
|
|
759
|
+
- *Cancel / abort cleanup* — an abort sends ACP `session/cancel` and lets the agent end its own turn (`awaitAcpPromptTurn` in `pi-extensions/lib/acp/backend.ts`); process-group teardown follows only after a bounded grace. A reuse turn the agent closed on `session/cancel` keeps its live session; a cancelled first turn, an escalation or a pre-prompt abort drops it, so the next turn bootstraps a new one (the "What an abort leaves" row in Gate pointers, §1B.7). Dedicated `smoke-cancel` retired; invariant in code.
|
|
573
760
|
|
|
574
761
|
### Evidence preservation when a problem occurs
|
|
575
762
|
|
|
576
763
|
```bash
|
|
577
764
|
pgrep -af 'claude-agent-acp|codex-acp' || true
|
|
578
|
-
|
|
765
|
+
ls ~/.pi/agent/cache/entwurf/sessions/ | tail # persisted pi:<sessionId> mappings (docs/setup-clean-host.md "Session reuse and compaction"); names only, never other sessions' bodies
|
|
579
766
|
ls ~/.pi/agent/sessions/--*--/*_${SESSION_ID}.jsonl 2>/dev/null
|
|
580
767
|
# ACP: the turn's lifecycle notices and stopReason live in that pi session file
|
|
581
768
|
```
|
|
582
769
|
|
|
583
|
-
Also preserve: the exact calls used, full stdout/stderr, the
|
|
770
|
+
Also preserve: the exact calls used, full stdout/stderr, the session's own pi transcript path, cache-directory changes, and the expected-vs-actual difference.
|
|
584
771
|
|
|
585
772
|
### History (pointer)
|
|
586
773
|
|
|
774
|
+
The 48-assertion / MUST 24/0/0 / 475/475 numbers the old surface banner carried are the 0.21.0 cut's dated receipt, kept in [BASELINE.md](./BASELINE.md)'s Native Codex Linux home-topology row. A later candidate's acceptance is its own receipt in BASELINE/CHANGELOG. Retired v1 verbs and bridge implementations belong only in CHANGELOG/git.
|
|
775
|
+
|
|
776
|
+
|
|
587
777
|
The full R2R run history (2026-04-27 → 2026-05-29, pi-shell-acp era), the per-claim evidence ledger (load-bearing claims with level-reached / blind spot / next test, maintained through 0.5.x–0.8.x), and the experimental L3–L5 tracks (4-cell verifier×subject matrix with on-disk corroboration; long-haul soak; direct-native parity panel) live in **CHANGELOG.md and git history**. Evidence reached **L2** (cross-vendor + reverse-direction MCP calls); L3 is partially exercised by the process/session-file checks above; the honest gap is **L3 → L5**. The most recent recorded floor baseline is in [BASELINE.md](./BASELINE.md)'s HISTORY section.
|