@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.
Files changed (88) hide show
  1. package/AGENTS.md +1 -1
  2. package/BASELINE.md +116 -397
  3. package/CHANGELOG.md +191 -2
  4. package/CONTRIBUTING.md +4 -4
  5. package/DELIVERY.md +2 -2
  6. package/ENTWURF-CLI.json +1 -1
  7. package/ENTWURF.json +10 -4
  8. package/README.md +11 -8
  9. package/VERIFY.md +333 -143
  10. package/demo/README.md +1 -1
  11. package/demo/demo-baseline.sh +1 -1
  12. package/demo/demo.sh +1 -1
  13. package/docs/acp-backend-rail.md +248 -34
  14. package/docs/setup-clean-host.md +75 -80
  15. package/mcp/entwurf-bridge/dist/ENTWURF.json +10 -4
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/acp-client.js +1 -1
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +90 -14
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/config.js +4 -9
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/context.js +15 -0
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/model-ids.js +9 -12
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +41 -56
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +33 -6
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +4 -1
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-mailbox-body.js +1 -1
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +2 -1
  28. package/package.json +14 -14
  29. package/pi/pi-durable/carrier/harness-setup.js +1 -1
  30. package/pi/pi-durable/carrier/subagent.js +1 -1
  31. package/pi/pi-durable/overlay/upstream-pin.json +15 -15
  32. package/pi/settings.reference.json +0 -1
  33. package/pi-extensions/acp-provider.ts +12 -6
  34. package/pi-extensions/lib/acp/acp-client.ts +6 -7
  35. package/pi-extensions/lib/acp/backend-adapter.ts +139 -15
  36. package/pi-extensions/lib/acp/backend.ts +261 -32
  37. package/pi-extensions/lib/acp/config.ts +4 -9
  38. package/pi-extensions/lib/acp/context.ts +17 -0
  39. package/pi-extensions/lib/acp/event-mapper.ts +236 -17
  40. package/pi-extensions/lib/acp/model-ids.js +9 -12
  41. package/pi-extensions/lib/acp/models.ts +46 -57
  42. package/pi-extensions/lib/acp/tool-surface.ts +34 -6
  43. package/pi-extensions/lib/entwurf-control-rpc.ts +5 -1
  44. package/pi-extensions/lib/fresh-call-composition.ts +37 -3
  45. package/pi-extensions/lib/herdr-fresh-call.ts +3 -1
  46. package/pi-extensions/lib/meta-mailbox-body.ts +1 -1
  47. package/pi-extensions/lib/mux-fresh-call.ts +3 -1
  48. package/pi-extensions/meta-bridge-pi-durable.ts +1 -1
  49. package/run.sh +62 -120
  50. package/scripts/check-acp-carrier-augment.ts +3 -21
  51. package/scripts/check-acp-prompt-lifecycle.ts +24 -3
  52. package/scripts/check-acp-provider-surface.ts +17 -26
  53. package/scripts/check-acp-session-reuse.ts +23 -4
  54. package/scripts/check-acp-stop-reason.ts +22 -3
  55. package/scripts/check-acp-stream-hooks.ts +24 -3
  56. package/scripts/check-acp-usage-accounting.ts +53 -24
  57. package/scripts/check-copilot-receive-arm.ts +19 -2
  58. package/scripts/check-entwurf-v2-surface.ts +7 -21
  59. package/scripts/check-fresh-call-dispatch.ts +9 -3
  60. package/scripts/check-gate-qualification.ts +6 -6
  61. package/scripts/check-herdr-fresh-call.ts +1 -0
  62. package/scripts/check-install-surface.ts +6 -0
  63. package/scripts/check-pi-durable-send.ts +4 -1
  64. package/scripts/check-probe-ordering.ts +34 -24
  65. package/scripts/check-release-gate-outcomes.ts +9 -23
  66. package/scripts/lib/codex-fresh-source-receipts.ts +12 -6
  67. package/scripts/lib/probe-cli-target.ts +3 -2
  68. package/scripts/mutants/acp-augment.json +0 -26
  69. package/scripts/mutants/acp-cortex.json +10 -183
  70. package/scripts/mutants/acp-foreground-only.json +11 -0
  71. package/scripts/mutants/acp-launch-namespace.json +3 -1
  72. package/scripts/mutants/acp-prompt-lifecycle.json +2 -2
  73. package/scripts/mutants/acp-set-model-readback.json +488 -0
  74. package/scripts/mutants/agent-guidance.json +2 -2
  75. package/scripts/mutants/codex-native.json +2 -2
  76. package/scripts/mutants/control-send-receipt.json +47 -7
  77. package/scripts/mutants/mux-fresh-call.json +12 -1
  78. package/scripts/mutants/pack-install.json +4 -4
  79. package/scripts/mutants/pi-floor.json +8 -10
  80. package/scripts/mutants/release-gate.json +3 -3
  81. package/scripts/mutants/v2-surface.json +4 -6
  82. package/scripts/raw-acp-compaction-measure/probe.ts +8 -2
  83. package/scripts/smoke-acp-cortex-live.ts +4 -408
  84. package/scripts/smoke-acp-ordering-probe-live.ts +7 -1
  85. package/scripts/smoke-acp-session-reuse-live.ts +11 -2
  86. package/scripts/smoke-acp-v2-send-live.ts +1 -1
  87. package/scripts/smoke-herdr-raw-install-live.sh +4 -4
  88. package/scripts/check-acp-cortex.ts +0 -710
@@ -23,6 +23,494 @@
23
23
  "timeoutSeconds": 60,
24
24
  "signature": "[QK:ACP-CLAUDE-SET-MODEL-ALIAS-EXACT]",
25
25
  "signatureSource": "pi-extensions/lib/acp/backend-adapter.test.ts"
26
+ },
27
+ {
28
+ "claim": "ACP-CLAUDE-THINKING-MENU",
29
+ "title": "the curated Claude rows register no thinkingLevelMap — pi's menu offers off/minimal the driver cannot carry and hides xhigh/max it can",
30
+ "subject": "pi-extensions/lib/acp/models.ts",
31
+ "find": ["\t\tthinkingLevelMap: claudeAcpThinkingLevelMap(m.thinkingLevelMap),"],
32
+ "replace": [""],
33
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
34
+ "timeoutSeconds": 60,
35
+ "signature": "[QK:ACP-CLAUDE-THINKING-MENU]",
36
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
37
+ },
38
+ {
39
+ "claim": "ACP-CLAUDE-THINKING-REFUSE-UNMAPPED",
40
+ "title": "any mapped string passes as an effort — a map value the driver does not offer reaches the wire instead of a named refusal",
41
+ "subject": "pi-extensions/lib/acp/backend-adapter.ts",
42
+ "find": ["\tif (typeof value === \"string\" && CLAUDE_EFFORT_VALUE_SET.has(value)) return value;"],
43
+ "replace": ["\tif (typeof value === \"string\") return value;"],
44
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
45
+ "timeoutSeconds": 60,
46
+ "signature": "[QK:ACP-CLAUDE-THINKING-REFUSE-UNMAPPED]",
47
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
48
+ },
49
+ {
50
+ "claim": "ACP-CLAUDE-EFFORT-READBACK",
51
+ "title": "the set-effort answer is no longer read back — the turn runs at whatever effort the driver kept while pi shows the requested level",
52
+ "subject": "pi-extensions/lib/acp/backend-adapter.ts",
53
+ "find": ["\t\tconfirmClaudeEffortAnswer(answer, modelId, value);"],
54
+ "replace": ["\t\tvoid answer;"],
55
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
56
+ "timeoutSeconds": 60,
57
+ "signature": "[QK:ACP-CLAUDE-EFFORT-READBACK]",
58
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
59
+ },
60
+ {
61
+ "claim": "ACP-THINKING-NEW-SET",
62
+ "title": "a new session never sets effort — the first turn runs at the vendor default whatever level pi selected",
63
+ "subject": "pi-extensions/lib/acp/backend.ts",
64
+ "find": [
65
+ "\t\t\t\t\tadapter.enforceThinking({ connection, acpSessionId, modelId: model.id, value: thinkingValue }),"
66
+ ],
67
+ "replace": ["\t\t\t\t\tPromise.resolve(),"],
68
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
69
+ "timeoutSeconds": 60,
70
+ "signature": "[QK:ACP-THINKING-NEW-SET]",
71
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
72
+ },
73
+ {
74
+ "claim": "ACP-THINKING-REUSE-SET",
75
+ "title": "a reused session never re-sets a changed level — the operator's new level is shown but the live conversation keeps the old effort",
76
+ "subject": "pi-extensions/lib/acp/backend.ts",
77
+ "find": [
78
+ "\t\t\tif (thinkingValue !== undefined && adapter.enforceThinking && session.thinkingValue !== thinkingValue) {"
79
+ ],
80
+ "replace": [
81
+ "\t\t\tif (thinkingValue !== undefined && adapter.enforceThinking && session.thinkingValue === undefined) {"
82
+ ],
83
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
84
+ "timeoutSeconds": 60,
85
+ "signature": "[QK:ACP-THINKING-REUSE-SET]",
86
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
87
+ },
88
+ {
89
+ "claim": "ACP-THINKING-READBACK-NOTICE",
90
+ "title": "a new session sets effort without telling the operator — the read-back level is invisible in pi, so a changed menu level and the driver's answer cannot be compared",
91
+ "subject": "pi-extensions/lib/acp/backend.ts",
92
+ "find": [
93
+ "\t\t\t\tsession.thinkingValue = thinkingValue;\n\t\t\t\t// Visible like the model lock: the operator sees the effort the driver read back.\n\t\t\t\tpushAcpLifecycleNotice(state, `effort ${thinkingValue} read back`);"
94
+ ],
95
+ "replace": ["\t\t\t\tsession.thinkingValue = thinkingValue;"],
96
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
97
+ "timeoutSeconds": 60,
98
+ "signature": "[QK:ACP-THINKING-READBACK-NOTICE]",
99
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
100
+ },
101
+ {
102
+ "claim": "ACP-THINKING-REUSE-ABORT",
103
+ "title": "an abort while a reuse turn waits for the effort answer is not heard — ESC settles only when the driver answers or the 30s bootstrap timeout fires",
104
+ "subject": "pi-extensions/lib/acp/backend.ts",
105
+ "find": ["\tif (!signal) return p;"],
106
+ "replace": ["\treturn p;"],
107
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
108
+ "timeoutSeconds": 120,
109
+ "signature": "[QK:ACP-THINKING-REUSE-ABORT]",
110
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
111
+ },
112
+ {
113
+ "claim": "ACP-CANCEL-NOTICE-REUSE-KEPT",
114
+ "title": "a reuse turn the agent cancelled keeps its live session without telling the operator — they cannot tell whether to continue or start over",
115
+ "subject": "pi-extensions/lib/acp/backend.ts",
116
+ "find": ["\t\t\t\tpushAcpLifecycleNotice(state, ACP_CANCEL_KEPT_NOTICE);"],
117
+ "replace": [""],
118
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
119
+ "timeoutSeconds": 60,
120
+ "signature": "[QK:ACP-CANCEL-NOTICE-REUSE-KEPT]",
121
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
122
+ },
123
+ {
124
+ "claim": "ACP-CANCEL-NOTICE-NEW-CLOSED",
125
+ "title": "a cancelled first turn claims the live session was kept although it was closed — the next message silently opens a new conversation",
126
+ "subject": "pi-extensions/lib/acp/backend.ts",
127
+ "find": ["\t\t\t\tpushAcpLifecycleNotice(state, retain ? ACP_CANCEL_KEPT_NOTICE : ACP_CANCEL_CLOSED_NOTICE);"],
128
+ "replace": ["\t\t\t\tpushAcpLifecycleNotice(state, ACP_CANCEL_KEPT_NOTICE);"],
129
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
130
+ "timeoutSeconds": 60,
131
+ "signature": "[QK:ACP-CANCEL-NOTICE-NEW-CLOSED]",
132
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
133
+ },
134
+ {
135
+ "claim": "ACP-THINKING-REUSE-ABORT-LATE",
136
+ "title": "an abort that arrives while a reuse turn waits for the effort answer is never heard — only an abort raised before the wait is honoured, so a real ESC waits for the driver or the 30s bound",
137
+ "subject": "pi-extensions/lib/acp/backend.ts",
138
+ "find": [
139
+ "\t\tonAbort = () => reject(new Error(\"entwurf: aborted by the operator before the prompt was sent\"));\n\t\tif (signal.aborted) onAbort();\n\t\telse signal.addEventListener(\"abort\", onAbort, { once: true });"
140
+ ],
141
+ "replace": [
142
+ "\t\tonAbort = () => reject(new Error(\"entwurf: aborted by the operator before the prompt was sent\"));\n\t\tif (signal.aborted) onAbort();\n\t\telse void signal;"
143
+ ],
144
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
145
+ "timeoutSeconds": 90,
146
+ "signature": "[QK:ACP-THINKING-REUSE-ABORT-LATE]",
147
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
148
+ },
149
+ {
150
+ "claim": "ACP-REBUILD-ABORTED-STATUS",
151
+ "title": "a rebuilt session reads an aborted turn that left text as a finished one — the vendor's rejection text alone makes a started command look like it never ran",
152
+ "subject": "pi-extensions/lib/acp/context.ts",
153
+ "find": [
154
+ "\t\t\t\treturn text ? `Assistant: ${text}\\n${ABORTED_TURN_STATUS}` : `Assistant: ${ABORTED_TURN_STATUS}`;"
155
+ ],
156
+ "replace": ["\t\t\t\treturn text ? `Assistant: ${text}` : `Assistant: ${ABORTED_TURN_STATUS}`;"],
157
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
158
+ "timeoutSeconds": 60,
159
+ "signature": "[QK:ACP-REBUILD-ABORTED-STATUS]",
160
+ "signatureSource": "pi-extensions/lib/acp/context.test.ts"
161
+ },
162
+ {
163
+ "claim": "ACP-REBUILD-ABORTED-EMPTY",
164
+ "title": "an aborted turn that left no text vanishes from the rebuilt transcript — the new session never learns a turn was cut",
165
+ "subject": "pi-extensions/lib/acp/context.ts",
166
+ "find": [
167
+ "\t\t\t\treturn text ? `Assistant: ${text}\\n${ABORTED_TURN_STATUS}` : `Assistant: ${ABORTED_TURN_STATUS}`;"
168
+ ],
169
+ "replace": ["\t\t\t\treturn text ? `Assistant: ${text}\\n${ABORTED_TURN_STATUS}` : undefined;"],
170
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
171
+ "timeoutSeconds": 60,
172
+ "signature": "[QK:ACP-REBUILD-ABORTED-EMPTY]",
173
+ "signatureSource": "pi-extensions/lib/acp/context.test.ts"
174
+ },
175
+ {
176
+ "claim": "ACP-REUSE-LATE-UPDATE-PRE-PROMPT",
177
+ "title": "a reuse turn routes the live session's updates to its stream before its own prompt is sent — a late update of the previous, cancelled turn arriving during the effort set is shown and sealed as this turn's answer",
178
+ "subject": "pi-extensions/lib/acp/backend.ts",
179
+ "find": ["\t\t\tpushAcpLifecycleNotice(state, \"reusing live session\");\n\t\t\tsession.busy = true;"],
180
+ "replace": [
181
+ "\t\t\tpushAcpLifecycleNotice(state, \"reusing live session\");\n\t\t\tsession.busy = true;\n\t\t\tsession.activePromptHandler = makePromptHandler(session);"
182
+ ],
183
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
184
+ "timeoutSeconds": 60,
185
+ "signature": "[QK:ACP-REUSE-LATE-UPDATE-PRE-PROMPT]",
186
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
187
+ },
188
+ {
189
+ "claim": "ACP-ROWS-TEXT-ONLY-INPUT",
190
+ "title": "the ACP rows advertise image input again — pi accepts an attachment the rail only ever sends as an `[image omitted]` marker",
191
+ "subject": "pi-extensions/lib/acp/models.ts",
192
+ "find": ["const ACP_ROW_INPUT: (\"text\" | \"image\")[] = [\"text\"];"],
193
+ "replace": ["const ACP_ROW_INPUT: (\"text\" | \"image\")[] = [\"text\", \"image\"];"],
194
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
195
+ "timeoutSeconds": 60,
196
+ "signature": "[QK:ACP-ROWS-TEXT-ONLY-INPUT]",
197
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
198
+ },
199
+ {
200
+ "claim": "ACP-CORTEX-DISABLED",
201
+ "title": "a retired Cortex model loses its named refusal at the turn resolver",
202
+ "subject": "pi-extensions/lib/acp/backend-adapter.ts",
203
+ "find": ["if (modelId.toLowerCase().startsWith(CORTEX_MODEL_PREFIX)) {"],
204
+ "replace": ["if (false && modelId.toLowerCase().startsWith(CORTEX_MODEL_PREFIX)) {"],
205
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
206
+ "timeoutSeconds": 60,
207
+ "signature": "[QK:ACP-CORTEX-DISABLED]",
208
+ "signatureSource": "pi-extensions/lib/acp/cortex-admission.test.ts"
209
+ },
210
+ {
211
+ "claim": "ACP-CORTEX-LEGACY-NOT-CURATED",
212
+ "title": "retired Cortex ids become accepted by the exact launch admission again",
213
+ "subject": "pi-extensions/lib/acp/model-ids.js",
214
+ "find": ["const CURATED_ACP_MODEL_IDS = new Set(SUPPORTED_ANTHROPIC_MODEL_IDS);"],
215
+ "replace": [
216
+ "const CURATED_ACP_MODEL_IDS = new Set([...SUPPORTED_ANTHROPIC_MODEL_IDS, ...LEGACY_CORTEX_MODEL_IDS]);"
217
+ ],
218
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
219
+ "timeoutSeconds": 60,
220
+ "signature": "[QK:ACP-CORTEX-LEGACY-NOT-CURATED]",
221
+ "signatureSource": "pi-extensions/lib/acp/cortex-admission.test.ts"
222
+ },
223
+ {
224
+ "claim": "ACP-CORTEX-DIRECT-DISABLED",
225
+ "title": "the exported retired adapter can launch Cortex again",
226
+ "subject": "pi-extensions/lib/acp/backend-adapter.ts",
227
+ "find": ["\tresolveLaunch: cortexDisabled,"],
228
+ "replace": ["\tresolveLaunch: retiredCortexAdapter.resolveLaunch,"],
229
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
230
+ "timeoutSeconds": 60,
231
+ "signature": "[QK:ACP-CORTEX-DIRECT-DISABLED]",
232
+ "signatureSource": "pi-extensions/lib/acp/cortex-admission.test.ts"
233
+ },
234
+ {
235
+ "claim": "ACP-CORTEX-CONFIG-DISABLED",
236
+ "title": "an explicit Cortex backend selection reaches Claude instead of the named disabled refusal",
237
+ "subject": "pi-extensions/lib/acp/backend-adapter.ts",
238
+ "find": ["if (backend?.toLowerCase() === \"cortex\") cortexDisabled();"],
239
+ "replace": ["if (false && backend?.toLowerCase() === \"cortex\") cortexDisabled();"],
240
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
241
+ "timeoutSeconds": 60,
242
+ "signature": "[QK:ACP-CORTEX-CONFIG-DISABLED]",
243
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
244
+ },
245
+ {
246
+ "claim": "ACP-CORTEX-TURN-DISABLED",
247
+ "title": "the production turn resolver falls back to Claude instead of refusing a Cortex model",
248
+ "subject": "pi-extensions/lib/acp/backend.ts",
249
+ "find": ["({ adapter, nativeModelId } = resolveAcpBackendAdapter(model.id));"],
250
+ "replace": ["({ adapter, nativeModelId } = resolveAcpBackendAdapter(\"claude-opus-5-5\"));"],
251
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
252
+ "timeoutSeconds": 60,
253
+ "signature": "[QK:ACP-CORTEX-TURN-DISABLED]",
254
+ "signatureSource": "pi-extensions/lib/acp/backend.thinking.test.ts"
255
+ },
256
+ {
257
+ "claim": "ACP-SUMMARY-TURN-TOOLLESS",
258
+ "title": "the summary turn keeps the operator's tool surface — Pi's tool-less summary request reaches a Claude child that can still run Read/Bash/Edit/Write while summarizing",
259
+ "subject": "pi-extensions/lib/acp/backend.ts",
260
+ "find": ["\t\t\ttools: [],"],
261
+ "replace": ["\t\t\ttools: config.tools,"],
262
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
263
+ "timeoutSeconds": 60,
264
+ "signature": "[QK:ACP-SUMMARY-TURN-TOOLLESS]",
265
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
266
+ },
267
+ {
268
+ "claim": "ACP-SUMMARY-INSTRUCTIONS-RELAYED",
269
+ "title": "Pi's summarization instructions are dropped — the system message never reaches the wire, so Claude answers the bare conversation instead of writing Pi's checkpoint summary",
270
+ "subject": "pi-extensions/lib/acp/backend.ts",
271
+ "find": ["const instructions = getCurrentSystemPrompt(context.messages).trim();"],
272
+ "replace": ["const instructions = \"\";"],
273
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
274
+ "timeoutSeconds": 60,
275
+ "signature": "[QK:ACP-SUMMARY-INSTRUCTIONS-RELAYED]",
276
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
277
+ },
278
+ {
279
+ "claim": "ACP-SUMMARY-TURN-NO-NOTICE",
280
+ "title": "the summary turn emits lifecycle and tool notices — `[acp:]`/`[tool:]` lines join the text Pi stores as compaction.summary, which is what gets embedded",
281
+ "subject": "pi-extensions/lib/acp/backend.ts",
282
+ "find": ["state.quiet = true;"],
283
+ "replace": ["state.quiet = false;"],
284
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
285
+ "timeoutSeconds": 60,
286
+ "signature": "[QK:ACP-SUMMARY-TURN-NO-NOTICE]",
287
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
288
+ },
289
+ {
290
+ "claim": "ACP-SUMMARY-TURN-NOT-RETAINED",
291
+ "title": "the summary child is retained under a process-scoped policy — every /compact leaves one more idle Claude process behind under a key nobody reuses",
292
+ "subject": "pi-extensions/lib/acp/backend.ts",
293
+ "find": ["lifecyclePolicy: \"turn-scoped\","],
294
+ "replace": ["lifecyclePolicy: \"process-scoped\","],
295
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
296
+ "timeoutSeconds": 60,
297
+ "signature": "[QK:ACP-SUMMARY-TURN-NOT-RETAINED]",
298
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
299
+ },
300
+ {
301
+ "claim": "ACP-SUMMARY-REQUIRES-CACHE-RETENTION",
302
+ "title": "an empty tool surface alone admits the summary path — an ordinary turn with every tool excluded silently runs tool-less instead of refusing the unhonourable exclusion",
303
+ "subject": "pi-extensions/lib/acp/tool-surface.ts",
304
+ "find": ["return activeToolNames.length === 0 && cacheRetention === \"none\";"],
305
+ "replace": ["return activeToolNames.length === 0;"],
306
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
307
+ "timeoutSeconds": 60,
308
+ "signature": "[QK:ACP-SUMMARY-REQUIRES-CACHE-RETENTION]",
309
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
310
+ },
311
+ {
312
+ "claim": "ACP-COMPACT-CLOSES-CHILD",
313
+ "title": "a compaction leaves the conversation's Claude child running — the pre-compaction context stays resident until the next turn's prefix break, against GLG's close-right-after decision",
314
+ "subject": "pi-extensions/acp-provider.ts",
315
+ "find": ["closeRetainedAcpSession(ctx.sessionManager.getSessionId());"],
316
+ "replace": ["void ctx;"],
317
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
318
+ "timeoutSeconds": 60,
319
+ "signature": "[QK:ACP-COMPACT-CLOSES-CHILD]",
320
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
321
+ },
322
+ {
323
+ "claim": "ACP-SUMMARY-TURN-NO-SETTING-SOURCES",
324
+ "title": "the summary child inherits the operator's settingSources — CLAUDE.md, hooks and plugins from disk reach a turn that should carry only the carrier and Pi's instructions",
325
+ "subject": "pi-extensions/lib/acp/backend.ts",
326
+ "find": ["\t\t\tsettingSources: [],"],
327
+ "replace": ["\t\t\tsettingSources: config.settingSources,"],
328
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
329
+ "timeoutSeconds": 60,
330
+ "signature": "[QK:ACP-SUMMARY-TURN-NO-SETTING-SOURCES]",
331
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
332
+ },
333
+ {
334
+ "claim": "ACP-SUMMARY-VENDOR-CANCEL-NOT-KEPT",
335
+ "title": "a summary the backend cancelled without an abort from Pi is sealed as aborted — Pi keeps aborted text, so an incomplete summary becomes the session's checkpoint",
336
+ "subject": "pi-extensions/lib/acp/backend.ts",
337
+ "find": ["if (summaryTurnActive && verdict.stopReason === \"aborted\" && !signal?.aborted) {"],
338
+ "replace": ["if (false) {"],
339
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
340
+ "timeoutSeconds": 60,
341
+ "signature": "[QK:ACP-SUMMARY-VENDOR-CANCEL-NOT-KEPT]",
342
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
343
+ },
344
+ {
345
+ "claim": "ACP-SUMMARY-REQUIRES-EMPTY-SURFACE",
346
+ "title": "cacheRetention none alone admits the summary path — a request that declares tools loses its tools, MCP and augment and runs as a tool-less one-shot",
347
+ "subject": "pi-extensions/lib/acp/tool-surface.ts",
348
+ "find": ["return activeToolNames.length === 0 && cacheRetention === \"none\";"],
349
+ "replace": ["return cacheRetention === \"none\";"],
350
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
351
+ "timeoutSeconds": 60,
352
+ "signature": "[QK:ACP-SUMMARY-REQUIRES-EMPTY-SURFACE]",
353
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
354
+ },
355
+ {
356
+ "claim": "ACP-COMPACT-SPARES-TURN-IN-FLIGHT",
357
+ "title": "a compaction closes a session whose turn is still running — the reused child is killed under the prompt it is answering",
358
+ "subject": "pi-extensions/lib/acp/backend.ts",
359
+ "find": ["\tif (!session || session.busy || inFlightKeys.has(key)) return false;"],
360
+ "replace": ["\tif (!session) return false;"],
361
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
362
+ "timeoutSeconds": 60,
363
+ "signature": "[QK:ACP-COMPACT-SPARES-TURN-IN-FLIGHT]",
364
+ "signatureSource": "pi-extensions/lib/acp/backend.summary-turn.test.ts"
365
+ },
366
+ {
367
+ "claim": "ACP-TOOL-TITLE-SHOWN",
368
+ "title": "a call's concrete title is never shown while it runs — the operator reads 'Terminal' until the command has finished",
369
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
370
+ "find": [
371
+ "\t\tpushDisplayOnlyNotice(state, `\\n[tool:running] ${sanitizeNoticeFragment(title, NOTICE_TITLE_MAX)}\\n`);"
372
+ ],
373
+ "replace": ["\t\tvoid title;"],
374
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
375
+ "timeoutSeconds": 60,
376
+ "signature": "[QK:ACP-TOOL-TITLE-SHOWN]",
377
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
378
+ },
379
+ {
380
+ "claim": "ACP-TOOL-TITLE-ONCE",
381
+ "title": "an update carrying both a new title and a progress beat prints two running lines for one event",
382
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
383
+ "find": ["\t\telapsed === undefined &&\n"],
384
+ "replace": [""],
385
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
386
+ "timeoutSeconds": 60,
387
+ "signature": "[QK:ACP-TOOL-TITLE-ONCE]",
388
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
389
+ },
390
+ {
391
+ "claim": "ACP-TOOL-TITLE-REPEAT-SILENT",
392
+ "title": "every title update prints a running line — a repeated title shows the same command again",
393
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
394
+ "find": [
395
+ "\t\tsanitizeNoticeFragment(update.title, NOTICE_TITLE_MAX) !== sanitizeNoticeFragment(previous.title, NOTICE_TITLE_MAX)"
396
+ ],
397
+ "replace": ["\t\ttrue"],
398
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
399
+ "timeoutSeconds": 60,
400
+ "signature": "[QK:ACP-TOOL-TITLE-REPEAT-SILENT]",
401
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
402
+ },
403
+ {
404
+ "claim": "ACP-TOOL-OUTPUT-PREVIEW",
405
+ "title": "a finished tool shows no output preview — the operator sees only the one-line summary, as before",
406
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
407
+ "find": ["\t\t\tconst preview = previewOf(summary, failed);"],
408
+ "replace": ["\t\t\tconst preview = undefined as string | undefined;"],
409
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
410
+ "timeoutSeconds": 60,
411
+ "signature": "[QK:ACP-TOOL-OUTPUT-PREVIEW]",
412
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
413
+ },
414
+ {
415
+ "claim": "ACP-TOOL-OUTPUT-FAILURE-TAIL",
416
+ "title": "a failure previews the head of its output — the stderr and exit reason at the end are cut off",
417
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
418
+ "find": ["\tconst shown = failed ? lines.slice(-PREVIEW_MAX_LINES) : lines.slice(0, PREVIEW_MAX_LINES);"],
419
+ "replace": ["\tconst shown = lines.slice(0, PREVIEW_MAX_LINES);"],
420
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
421
+ "timeoutSeconds": 60,
422
+ "signature": "[QK:ACP-TOOL-OUTPUT-FAILURE-TAIL]",
423
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
424
+ },
425
+ {
426
+ "claim": "ACP-TOOL-OUTPUT-BOUNDED",
427
+ "title": "a preview is bounded by lines only — a few very long lines put kilobytes of output on screen",
428
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
429
+ "find": ["\treturn clipBytes(shown.join(\"\\n\"), PREVIEW_MAX_BYTES, failed);"],
430
+ "replace": ["\treturn shown.join(\"\\n\");"],
431
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
432
+ "timeoutSeconds": 60,
433
+ "signature": "[QK:ACP-TOOL-OUTPUT-BOUNDED]",
434
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
435
+ },
436
+ {
437
+ "claim": "ACP-COMPACTION-LINE",
438
+ "title": "the backend's own compaction shows no numbers — only the bare start/done tool pair",
439
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
440
+ "find": ["\tpushAcpLifecycleNotice(state, parts.join(\" \"));"],
441
+ "replace": ["\tvoid parts;"],
442
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
443
+ "timeoutSeconds": 60,
444
+ "signature": "[QK:ACP-COMPACTION-LINE]",
445
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
446
+ },
447
+ {
448
+ "claim": "ACP-COMPACTION-ONCE",
449
+ "title": "an enriching terminal update prints a second compaction line for the same compaction",
450
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
451
+ "find": ["\tif (observed.compactionShown) return;"],
452
+ "replace": ["\tif (observed.compactionShown === null) return;"],
453
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
454
+ "timeoutSeconds": 60,
455
+ "signature": "[QK:ACP-COMPACTION-ONCE]",
456
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
457
+ },
458
+ {
459
+ "claim": "ACP-COMPACTION-FAILED",
460
+ "title": "a failed compaction reads like a successful one — its line never says failed",
461
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
462
+ "find": [
463
+ "\tif (facts.error !== undefined && facts.error !== null && facts.error !== \"\") parts.push(\"failed\");"
464
+ ],
465
+ "replace": ["\tvoid facts.error;"],
466
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
467
+ "timeoutSeconds": 60,
468
+ "signature": "[QK:ACP-COMPACTION-FAILED]",
469
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
470
+ },
471
+ {
472
+ "claim": "ACP-NOTICE-NO-TERMINAL-CONTROL",
473
+ "title": "tool output and titles reach the terminal raw — an OSC 52 in a command's output writes the operator's clipboard, an OSC 0 retitles the window",
474
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
475
+ "find": ["\treturn text.replace(ANSI_SEQUENCE, \"\").replace(CONTROL_CHARS, \"\");"],
476
+ "replace": ["\treturn text;"],
477
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
478
+ "timeoutSeconds": 60,
479
+ "signature": "[QK:ACP-NOTICE-NO-TERMINAL-CONTROL]",
480
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
481
+ },
482
+ {
483
+ "claim": "ACP-NOTICE-ANSI-WHOLE",
484
+ "title": "only the escape byte is dropped — each sequence's parameters and payload (a clipboard base64, a colour code) stay on screen as text",
485
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
486
+ "find": ["\treturn text.replace(ANSI_SEQUENCE, \"\").replace(CONTROL_CHARS, \"\");"],
487
+ "replace": ["\treturn text.replace(CONTROL_CHARS, \"\");"],
488
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
489
+ "timeoutSeconds": 60,
490
+ "signature": "[QK:ACP-NOTICE-ANSI-WHOLE]",
491
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
492
+ },
493
+ {
494
+ "claim": "ACP-TOOL-OUTPUT-INDENT-KEPT",
495
+ "title": "a preview collapses each line's whitespace — a stack trace, YAML or diff loses its indentation",
496
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
497
+ "find": ["\t\t.map((line) => sanitizePreviewLine(line));"],
498
+ "replace": ["\t\t.map((line) => sanitizeNoticeFragment(line, PREVIEW_MAX_BYTES));"],
499
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
500
+ "timeoutSeconds": 60,
501
+ "signature": "[QK:ACP-TOOL-OUTPUT-INDENT-KEPT]",
502
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
503
+ },
504
+ {
505
+ "claim": "ACP-PREVIEW-MATCHES-PI",
506
+ "title": "a preview keeps characters Pi drops from tool output — U+FFF9..U+FFFB, which break width measurement, survive",
507
+ "subject": "pi-extensions/lib/acp/event-mapper.ts",
508
+ "find": ["/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F\\uFFF9-\\uFFFB]/g;"],
509
+ "replace": ["/[\\x00-\\x08\\x0B\\x0C\\x0E-\\x1F\\x7F-\\x9F]/g;"],
510
+ "gate": ["bash", "run.sh", "check-acp-set-model-readback"],
511
+ "timeoutSeconds": 60,
512
+ "signature": "[QK:ACP-PREVIEW-MATCHES-PI]",
513
+ "signatureSource": "pi-extensions/lib/acp/event-mapper.test.ts"
26
514
  }
27
515
  ]
28
516
  }
@@ -6,8 +6,8 @@
6
6
  "claim": "GUIDANCE-REVIEWED-REVISION",
7
7
  "title": "a valid Root revision advances beyond the independently reviewed payload revision while every history entry and decoded tool string remains valid",
8
8
  "subject": "ENTWURF.json",
9
- "find": ["\t\"revision\": 19,", "\t\"history\": ["],
10
- "replace": ["\t\"revision\": 20,", "\t\"history\": ["],
9
+ "find": ["\t\"revision\": 20,", "\t\"history\": ["],
10
+ "replace": ["\t\"revision\": 21,", "\t\"history\": ["],
11
11
  "gate": ["bash", "run.sh", "check-agent-guidance-beside"],
12
12
  "timeoutSeconds": 120,
13
13
  "signature": "[QK:GUIDANCE-REVIEWED-REVISION]",
@@ -715,9 +715,9 @@
715
715
  "claim": "CODEX-LIVE-RAW-CALLBACK-REQUIRED",
716
716
  "title": "a Pi callback with arbitrary bytes after its sender envelope is accepted as exact",
717
717
  "subject": "scripts/lib/codex-fresh-source-receipts.ts",
718
- "find": ["\tif (!text.startsWith(prefix) || !text.endsWith(suffix)) return null;"],
718
+ "find": ["\tconst suffix = \"</sender_info>\";"],
719
719
  "replace": [
720
- "\tif (!text.startsWith(prefix)) return null;\n\tconst suffixAt = text.indexOf(suffix, prefix.length);\n\tif (suffixAt < 0) return null;\n\ttext = text.slice(0, suffixAt + suffix.length); // mutant: discard callback suffix"
720
+ "\tconst suffix = \"</sender_info>\";\n\tconst suffixAt = text.indexOf(suffix);\n\tif (suffixAt >= 0) text = text.slice(0, suffixAt + suffix.length); // mutant: discard callback suffix"
721
721
  ],
722
722
  "gate": ["bash", "run.sh", "check-mux-fresh-call"],
723
723
  "timeoutSeconds": 180,
@@ -11,7 +11,8 @@
11
11
  "gate": ["bash", "run.sh", "check-control-send-receipt"],
12
12
  "timeoutSeconds": 600,
13
13
  "signature": "[QK:SEND-RECEIPT-IDLE-IS-SENT]",
14
- "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts"
14
+ "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts",
15
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
15
16
  },
16
17
  {
17
18
  "claim": "SEND-RECEIPT-BUSY-STEER-IS-QUEUED",
@@ -22,7 +23,8 @@
22
23
  "gate": ["bash", "run.sh", "check-control-send-receipt"],
23
24
  "timeoutSeconds": 600,
24
25
  "signature": "[QK:SEND-RECEIPT-BUSY-STEER-IS-QUEUED]",
25
- "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts"
26
+ "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts",
27
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
26
28
  },
27
29
  {
28
30
  "claim": "SEND-RECEIPT-BUSY-FOLLOWUP-IS-QUEUED",
@@ -33,7 +35,8 @@
33
35
  "gate": ["bash", "run.sh", "check-control-send-receipt"],
34
36
  "timeoutSeconds": 600,
35
37
  "signature": "[QK:SEND-RECEIPT-BUSY-FOLLOWUP-IS-QUEUED]",
36
- "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts"
38
+ "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts",
39
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
37
40
  },
38
41
  {
39
42
  "claim": "SEND-RECEIPT-UNKNOWN-IS-ACCEPTED-NOT-SENT",
@@ -44,7 +47,8 @@
44
47
  "gate": ["bash", "run.sh", "check-control-send-receipt"],
45
48
  "timeoutSeconds": 600,
46
49
  "signature": "[QK:SEND-RECEIPT-UNKNOWN-IS-ACCEPTED-NOT-SENT]",
47
- "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts"
50
+ "signatureSource": "pi-extensions/lib/control-send-receipt.test.ts",
51
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
48
52
  },
49
53
  {
50
54
  "claim": "SEND-BOUNDARY-CARRIED",
@@ -194,7 +198,7 @@
194
198
  "claim": "PI-CORE-PIN-TRACKS-FLOOR",
195
199
  "title": "the queue oracle's pi-agent-core pin drifts off the floor the rest of the pi runtime is pinned to, so the oracle keeps answering honestly — about a pi nobody in this repo runs",
196
200
  "subject": "package.json",
197
- "find": ["\"@earendil-works/pi-agent-core\": \"1.5.0\","],
201
+ "find": ["\"@earendil-works/pi-agent-core\": \"1.5.2\","],
198
202
  "replace": ["\"@earendil-works/pi-agent-core\": \"0.87.1\","],
199
203
  "gate": ["bash", "run.sh", "check-dep-versions"],
200
204
  "timeoutSeconds": 300,
@@ -240,15 +244,51 @@
240
244
  "title": "the caller-facing outcome list drops the native-push rail, so a caller reading the one blurb it reads before dispatching is told the control rail's vocabulary covers a rail that answers with a direct injection instead",
241
245
  "subject": "ENTWURF.json",
242
246
  "find": [
243
- "native-push INJECTION, a rejection, or lock-dirty. This receipt is not the colleague's reply or evidence of reading. EXISTING targets only; discover with "
247
+ "native-push INJECTION, a rejection, or lock-dirty. A receipt is not a reply or proof of reading. A local final is not delivery:"
244
248
  ],
245
249
  "replace": [
246
- "a rejection, or lock-dirty. This receipt is not the colleague's reply or evidence of reading. EXISTING targets only; discover with "
250
+ "a rejection, or lock-dirty. A receipt is not a reply or proof of reading. A local final is not delivery:"
247
251
  ],
248
252
  "gate": ["bash", "run.sh", "check-entwurf-v2-surface"],
249
253
  "timeoutSeconds": 300,
250
254
  "signature": "[QK:SEND-OUTCOME-LIST-NAMES-EVERY-RAIL]",
251
255
  "signatureSource": "scripts/check-entwurf-v2-surface.ts"
256
+ },
257
+ {
258
+ "claim": "PI-RECEIVED-REPLY-GUIDANCE",
259
+ "title": "the Pi receiver omits guidance for a replyable sender, so a local final can be mistaken for a reply",
260
+ "subject": "pi-extensions/lib/entwurf-control-rpc.ts",
261
+ "find": ["sender.replyable === true"],
262
+ "replace": ["sender.replyable === false"],
263
+ "gate": ["bash", "run.sh", "check-control-send-receipt"],
264
+ "timeoutSeconds": 300,
265
+ "signature": "[QK:PI-RECEIVED-REPLY-GUIDANCE]",
266
+ "signatureSource": "pi-extensions/entwurf-control.test.ts",
267
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
268
+ },
269
+ {
270
+ "claim": "MAILBOX-RECEIVED-REPLY-GUIDANCE",
271
+ "title": "the mailbox receiver's guidance drops the local-final boundary",
272
+ "subject": "pi-extensions/lib/meta-mailbox-body.ts",
273
+ "find": ["a local final is not delivery."],
274
+ "replace": ["a local final is delivery."],
275
+ "gate": ["bash", "run.sh", "check-control-send-receipt"],
276
+ "timeoutSeconds": 300,
277
+ "signature": "[QK:MAILBOX-RECEIVED-REPLY-GUIDANCE]",
278
+ "signatureSource": "pi-extensions/lib/entwurf-v2-mailbox.test.ts",
279
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
280
+ },
281
+ {
282
+ "claim": "NATIVE-PUSH-RECEIVED-REPLY-GUIDANCE",
283
+ "title": "the native-push receiver's guidance drops the no-send boundary",
284
+ "subject": "pi-extensions/lib/meta-mailbox-body.ts",
285
+ "find": ["Honor routing and no-send instructions;"],
286
+ "replace": ["Ignore routing and no-send instructions;"],
287
+ "gate": ["bash", "run.sh", "check-control-send-receipt"],
288
+ "timeoutSeconds": 300,
289
+ "signature": "[QK:NATIVE-PUSH-RECEIVED-REPLY-GUIDANCE]",
290
+ "signatureSource": "pi-extensions/lib/entwurf-v2-native-push.test.ts",
291
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
252
292
  }
253
293
  ]
254
294
  }