@junghanacs/entwurf 0.35.0 → 0.35.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/CHANGELOG.md +129 -0
- package/VERIFY.md +5 -4
- package/docs/acp-backend-rail.md +28 -2
- package/docs/setup-clean-host.md +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +46 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/model-ids.js +67 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/models.js +9 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +11 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +27 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +2 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +13 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +119 -11
- package/package.json +2 -2
- package/pi-extensions/lib/acp/backend-adapter.ts +52 -2
- package/pi-extensions/lib/acp/model-ids.js +77 -0
- package/pi-extensions/lib/acp/models.ts +15 -22
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +12 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +25 -1
- package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
- package/pi-extensions/lib/mux-fresh-call.ts +3 -0
- package/pi-extensions/lib/resume-launch-identity.ts +12 -4
- package/pi-extensions/meta-bridge-pi-durable.ts +153 -13
- package/run.sh +81 -20
- package/scripts/check-acp-backend-preflight.ts +10 -2
- package/scripts/check-acp-cortex.ts +7 -6
- package/scripts/check-acp-prompt-lifecycle.ts +2 -2
- package/scripts/check-acp-provider-surface.ts +1 -1
- package/scripts/check-acp-session-reuse.ts +5 -5
- package/scripts/check-acp-stop-reason.ts +2 -2
- package/scripts/check-acp-stream-hooks.ts +2 -2
- package/scripts/check-acp-usage-accounting.ts +2 -2
- package/scripts/check-fresh-call-dispatch.ts +47 -4
- package/scripts/check-gate-qualification.ts +6 -4
- package/scripts/check-probe-ordering.ts +13 -6
- package/scripts/check-resume-launch-identity.ts +38 -0
- package/scripts/mutants/acp-cortex.json +17 -8
- package/scripts/mutants/acp-set-model-readback.json +28 -0
- package/scripts/mutants/fresh-call-dispatch.json +11 -0
- package/scripts/mutants/herdr-dev-checkout.json +70 -0
- package/scripts/mutants/pi-durable.json +117 -0
- package/scripts/mutants/resume-launch-identity.json +15 -0
- package/scripts/mutants/v2-visible-resume.json +11 -0
- package/scripts/resolve-acp-bridge.ts +1 -1
- package/scripts/smoke-acp-bundled-mcp-live.ts +1 -1
- package/scripts/smoke-acp-carrier-augment-live.ts +1 -1
- package/scripts/smoke-acp-long-turn-live.ts +1 -1
- package/scripts/smoke-acp-mcp-live.ts +1 -1
- package/scripts/smoke-acp-memory-containment-live.ts +1 -1
- package/scripts/smoke-acp-ordering-probe-live.ts +1 -1
- package/scripts/smoke-acp-overlay-live.ts +1 -1
- package/scripts/smoke-acp-provider-live.ts +1 -1
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-acp-session-reuse-live.ts +1 -1
- package/scripts/smoke-acp-skill-live.ts +1 -1
- package/scripts/smoke-acp-socket-citizen-live.ts +2 -2
- package/scripts/smoke-acp-v2-send-live.ts +1 -1
- package/scripts/smoke-entwurf-chain-live.ts +1 -1
- package/scripts/smoke-mux-lifecycle-live.ts +1 -1
|
@@ -51,8 +51,8 @@ function tctx(messages: Context["messages"]): TranscriptContext {
|
|
|
51
51
|
return normalizeContext({ tools: PI_DECLARED_TOOLS, messages });
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
const sonnet = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
55
|
-
const opus = { id: "claude-opus-5" } as unknown as Model<Api>;
|
|
54
|
+
const sonnet = { id: "claude-sonnet-5-5" } as unknown as Model<Api>;
|
|
55
|
+
const opus = { id: "claude-opus-5-5" } as unknown as Model<Api>;
|
|
56
56
|
|
|
57
57
|
type Stream = AsyncIterable<AssistantMessageEvent> & {
|
|
58
58
|
result: () => Promise<{ stopReason: string; errorMessage?: string }>;
|
|
@@ -154,7 +154,7 @@ function makeHarness(recordDir: string, config: any = DEFAULT_RESOLVED_CONFIG, e
|
|
|
154
154
|
newSessionSeq++;
|
|
155
155
|
return { sessionId: `ACP-${newSessionSeq}` };
|
|
156
156
|
},
|
|
157
|
-
setSessionConfigOption: async () => ({}),
|
|
157
|
+
setSessionConfigOption: async (p: any) => ({ configOptions: [{ id: "model", currentValue: p.value }] }),
|
|
158
158
|
prompt: async ({ sessionId, prompt }: any) => {
|
|
159
159
|
promptCalls.push({ sessionId, text: prompt.map((b: { text: string }) => b.text).join("\n") });
|
|
160
160
|
if (block) await block;
|
|
@@ -505,7 +505,7 @@ try {
|
|
|
505
505
|
);
|
|
506
506
|
const d1 = deltaText(t1);
|
|
507
507
|
const iPrep = d1.indexOf("[acp: preparing claude session]");
|
|
508
|
-
const iReady = d1.indexOf("[acp: session ready model=claude-sonnet-5]");
|
|
508
|
+
const iReady = d1.indexOf("[acp: session ready model=claude-sonnet-5-5]");
|
|
509
509
|
const iSent = d1.indexOf("[acp: sending prompt]");
|
|
510
510
|
assert.ok(
|
|
511
511
|
iPrep >= 0 && iReady > iPrep && iSent > iReady,
|
|
@@ -533,7 +533,7 @@ try {
|
|
|
533
533
|
const ctxWithNotice = tctx([
|
|
534
534
|
{ role: "user", content: "real user line", timestamp: 0 },
|
|
535
535
|
mkAssistant([
|
|
536
|
-
{ type: "text", text: "\n[acp: session ready model=claude-sonnet-5]\n", textSignature: MARKER },
|
|
536
|
+
{ type: "text", text: "\n[acp: session ready model=claude-sonnet-5-5]\n", textSignature: MARKER },
|
|
537
537
|
{ type: "text", text: "real assistant line" },
|
|
538
538
|
]),
|
|
539
539
|
]);
|
|
@@ -55,7 +55,7 @@ import { pathToFileURL } from "node:url";
|
|
|
55
55
|
import type { Api, AssistantMessageEvent, Model } from "@earendil-works/pi-ai";
|
|
56
56
|
import { normalizeContext } from "@earendil-works/pi-ai";
|
|
57
57
|
|
|
58
|
-
const sonnet = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
58
|
+
const sonnet = { id: "claude-sonnet-5-5" } as unknown as Model<Api>;
|
|
59
59
|
|
|
60
60
|
type Stream = AsyncIterable<AssistantMessageEvent> & {
|
|
61
61
|
result: () => Promise<{ stopReason: string; errorMessage?: string }>;
|
|
@@ -124,7 +124,7 @@ function makeHarness(recordDir: string, wireReason: string | null) {
|
|
|
124
124
|
createConnection: (_child: any, handlers: any) => ({
|
|
125
125
|
initialize: async () => ({ agentCapabilities: {} }),
|
|
126
126
|
newSession: async () => ({ sessionId: "ACP-1" }),
|
|
127
|
-
setSessionConfigOption: async () => ({}),
|
|
127
|
+
setSessionConfigOption: async (p: any) => ({ configOptions: [{ id: "model", currentValue: p.value }] }),
|
|
128
128
|
prompt: async ({ sessionId }: any) => {
|
|
129
129
|
await handlers.sessionUpdate({
|
|
130
130
|
update: { sessionUpdate: "agent_message_chunk", content: { type: "text", text: "PARTIAL" } },
|
|
@@ -35,7 +35,7 @@ import { pathToFileURL } from "node:url";
|
|
|
35
35
|
import type { Api, AssistantMessageEvent, Message, Model, TranscriptContext } from "@earendil-works/pi-ai";
|
|
36
36
|
import { normalizeContext } from "@earendil-works/pi-ai";
|
|
37
37
|
|
|
38
|
-
const sonnet = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
38
|
+
const sonnet = { id: "claude-sonnet-5-5" } as unknown as Model<Api>;
|
|
39
39
|
|
|
40
40
|
type Stream = AsyncIterable<AssistantMessageEvent>;
|
|
41
41
|
|
|
@@ -93,7 +93,7 @@ function makeHarness(recordDir: string) {
|
|
|
93
93
|
const makeConnection = (_handlers: any) => ({
|
|
94
94
|
initialize: async () => ({ agentCapabilities: {} }),
|
|
95
95
|
newSession: async () => ({ sessionId: "ACP-1" }),
|
|
96
|
-
setSessionConfigOption: async () => ({}),
|
|
96
|
+
setSessionConfigOption: async (p: any) => ({ configOptions: [{ id: "model", currentValue: p.value }] }),
|
|
97
97
|
prompt: async (params: any) => {
|
|
98
98
|
// Deep-cloned: the capture must be the bytes that crossed the seam, not a
|
|
99
99
|
// live reference a later mutation could rewrite.
|
|
@@ -61,7 +61,7 @@ import type {
|
|
|
61
61
|
import { isContextOverflow, normalizeContext } from "@earendil-works/pi-ai";
|
|
62
62
|
import { calculateContextTokens } from "@earendil-works/pi-coding-agent";
|
|
63
63
|
|
|
64
|
-
const claude = { id: "claude-sonnet-5" } as unknown as Model<Api>;
|
|
64
|
+
const claude = { id: "claude-sonnet-5-5" } as unknown as Model<Api>;
|
|
65
65
|
const cortex = { id: "cortex-auto" } as unknown as Model<Api>;
|
|
66
66
|
|
|
67
67
|
type Stream = AsyncIterable<AssistantMessageEvent>;
|
|
@@ -160,7 +160,7 @@ function makeHarness(recordDir: string, scripts: TurnScript[]) {
|
|
|
160
160
|
newSessionCalls++;
|
|
161
161
|
return { sessionId: "ACP-1" };
|
|
162
162
|
},
|
|
163
|
-
setSessionConfigOption: async () => ({}),
|
|
163
|
+
setSessionConfigOption: async (p: any) => ({ configOptions: [{ id: "model", currentValue: p.value }] }),
|
|
164
164
|
prompt: async ({ sessionId }: any) => {
|
|
165
165
|
const script = scripts[turnIndex++] ?? {};
|
|
166
166
|
const update: Record<string, unknown> = { sessionUpdate: "usage_update" };
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
* FCD-RENDER-PER-RAIL each rail renders its own receipt; no universal tmux prose
|
|
27
27
|
* FCD-HERDR-VIEW-NOT-ADDRESS the herdr receipt says its coordinates are a view
|
|
28
28
|
* FCD-RECOVERY-VISIBLE a post-split failure shows closed vs orphan-unreclaimed:reason
|
|
29
|
+
* FCD-ACP-MODEL-EXACT a pi `entwurf/<id>` that is not an exact curated ACP id refuses on
|
|
30
|
+
* either rail before anything runs (#128)
|
|
29
31
|
*/
|
|
30
32
|
|
|
31
33
|
import assert from "node:assert/strict";
|
|
@@ -112,10 +114,18 @@ async function main(): Promise<void> {
|
|
|
112
114
|
// Up to the FIRST statement of the tmux path, which is the target capability question
|
|
113
115
|
// (#95 lane B added a caller-side one beside it, so `const missing =` is no longer the
|
|
114
116
|
// boundary — it is the line that FOLDS the two).
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
117
|
+
// Fail closed on the anchors: a renamed or reordered line would otherwise slice an EMPTY branch,
|
|
118
|
+
// and every negative `!herdrBranch.includes(…)` below would pass on nothing (#128 review D2).
|
|
119
|
+
// The slice ends at the herdr branch's OWN return, not at a tmux-path statement, so a mutant
|
|
120
|
+
// that edits the tmux path cannot move this boundary and fail this cell for its reason.
|
|
121
|
+
const herdrStart = dispatchCode.indexOf('if (selectFreshCallRail(env) === "herdr")');
|
|
122
|
+
const herdrReturn = 'return { rail: "herdr", result: await herdrFreshCall(';
|
|
123
|
+
const herdrReturnAt = dispatchCode.indexOf(herdrReturn);
|
|
124
|
+
const herdrBranch =
|
|
125
|
+
herdrStart >= 0 && herdrReturnAt > herdrStart
|
|
126
|
+
? dispatchCode.slice(herdrStart, herdrReturnAt + herdrReturn.length)
|
|
127
|
+
: "";
|
|
128
|
+
const herdrBranchLocated = herdrBranch.includes("herdrFreshCall(");
|
|
119
129
|
|
|
120
130
|
// ── no fallback, either direction ────────────────────────────────────────────────────
|
|
121
131
|
const incomplete = await dispatchFreshCall(REQUEST, { HERDR_ENV: "1" }, recordingSpawn().spawn);
|
|
@@ -124,6 +134,37 @@ async function main(): Promise<void> {
|
|
|
124
134
|
incomplete.rail === "herdr" && !incomplete.result.ok && incomplete.result.reason === "herdr-context-missing",
|
|
125
135
|
);
|
|
126
136
|
|
|
137
|
+
// ── #128: an entwurf/<id> pi launch names an EXACT curated ACP id ───────────────────────
|
|
138
|
+
{
|
|
139
|
+
const herdrSpawn = recordingSpawn();
|
|
140
|
+
const pi = (model: string) => ({ ...REQUEST, model });
|
|
141
|
+
const herdrRetired = await dispatchFreshCall(pi("entwurf/claude-sonnet-5"), HERDR_ENV, herdrSpawn.spawn);
|
|
142
|
+
const tmuxRetired = await dispatchFreshCall(pi(" entwurf/claude-opus-5 "), {}, recordingSpawn().spawn);
|
|
143
|
+
const current = recordingSpawn();
|
|
144
|
+
const herdrCurrent = await dispatchFreshCall(pi("entwurf/claude-opus-5-5"), HERDR_ENV, current.spawn);
|
|
145
|
+
const cortex = await dispatchFreshCall(pi("entwurf/cortex-claude-sonnet-5"), {}, recordingSpawn().spawn);
|
|
146
|
+
const otherBackend = await dispatchFreshCall(
|
|
147
|
+
{ ...REQUEST, backend: "claude-code", model: "entwurf/claude-sonnet-5" },
|
|
148
|
+
{},
|
|
149
|
+
recordingSpawn().spawn,
|
|
150
|
+
);
|
|
151
|
+
const reasonOf = (d: Awaited<ReturnType<typeof dispatchFreshCall>>) => (d.result.ok ? null : d.result.reason);
|
|
152
|
+
ok(
|
|
153
|
+
"[QK:FCD-ACP-MODEL-EXACT] a pi sibling under the entwurf provider must name an EXACT curated ACP id: a retired Claude 5 id refuses as acp-model-not-curated on BOTH rails (trimmed like the rails read it) before herdr is asked anything, while the 5.5 id and a Cortex id pass through and another backend is not judged — Pi would otherwise open the retired id on a Cortex row by substring",
|
|
154
|
+
herdrRetired.rail === "herdr" &&
|
|
155
|
+
reasonOf(herdrRetired) === "acp-model-not-curated" &&
|
|
156
|
+
herdrSpawn.calls.length === 0 &&
|
|
157
|
+
tmuxRetired.rail === "tmux" &&
|
|
158
|
+
reasonOf(tmuxRetired) === "acp-model-not-curated" &&
|
|
159
|
+
reasonOf(herdrCurrent) !== "acp-model-not-curated" &&
|
|
160
|
+
current.calls.length > 0 &&
|
|
161
|
+
reasonOf(cortex) !== "acp-model-not-curated" &&
|
|
162
|
+
reasonOf(otherBackend) !== "acp-model-not-curated" &&
|
|
163
|
+
renderDispatchedFreshCall(herdrRetired).text.includes("exact curated ACP id") &&
|
|
164
|
+
renderDispatchedFreshCall(tmuxRetired).text.includes("exact curated ACP id"),
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
|
|
127
168
|
const nonPilot = recordingSpawn();
|
|
128
169
|
const refused = await dispatchFreshCall({ ...REQUEST, backend: "codex" }, HERDR_ENV, nonPilot.spawn);
|
|
129
170
|
ok(
|
|
@@ -132,6 +173,7 @@ async function main(): Promise<void> {
|
|
|
132
173
|
!refused.result.ok &&
|
|
133
174
|
refused.result.reason === "herdr-backend-unsupported" &&
|
|
134
175
|
nonPilot.calls.length === 0 &&
|
|
176
|
+
herdrBranchLocated &&
|
|
135
177
|
// And structurally: the herdr branch names NEITHER capability preflight — not the
|
|
136
178
|
// target one, and not the caller-seat one #95 lane B put beside it.
|
|
137
179
|
!herdrBranch.includes("codexFreshPreflight") &&
|
|
@@ -153,6 +195,7 @@ async function main(): Promise<void> {
|
|
|
153
195
|
!durableRefused.result.ok &&
|
|
154
196
|
durableRefused.result.reason === "herdr-backend-unsupported" &&
|
|
155
197
|
durable.calls.length === 0 &&
|
|
198
|
+
herdrBranchLocated &&
|
|
156
199
|
!herdrBranch.includes("piDurable"),
|
|
157
200
|
);
|
|
158
201
|
|
|
@@ -3441,6 +3441,7 @@ let manifestCount: number;
|
|
|
3441
3441
|
"acp-launch-namespace": 2,
|
|
3442
3442
|
"acp-overlay": 1,
|
|
3443
3443
|
"acp-prompt-lifecycle": 15,
|
|
3444
|
+
"acp-set-model-readback": 2,
|
|
3444
3445
|
"acp-stop-reason": 6,
|
|
3445
3446
|
"acp-stream-hooks": 10,
|
|
3446
3447
|
"acp-usage-accounting": 12,
|
|
@@ -3463,10 +3464,10 @@ let manifestCount: number;
|
|
|
3463
3464
|
"pi-bridge-sender": 4,
|
|
3464
3465
|
"pi-mcp-bridge": 2,
|
|
3465
3466
|
"pi-mcp-register": 3,
|
|
3466
|
-
"pi-durable":
|
|
3467
|
+
"pi-durable": 65,
|
|
3467
3468
|
"copilot-receive": 20,
|
|
3468
3469
|
"entwurf-peers": 1,
|
|
3469
|
-
"fresh-call-dispatch":
|
|
3470
|
+
"fresh-call-dispatch": 12,
|
|
3470
3471
|
"fresh-cut": 3,
|
|
3471
3472
|
"gate-qualification": 10,
|
|
3472
3473
|
"herdr-placement": 13,
|
|
@@ -3474,6 +3475,7 @@ let manifestCount: number;
|
|
|
3474
3475
|
"herdr-plugin-profile": 14,
|
|
3475
3476
|
"herdr-activation": 34,
|
|
3476
3477
|
"herdr-plugin-build": 20,
|
|
3478
|
+
"herdr-dev-checkout": 4,
|
|
3477
3479
|
"herdr-runtime-bootstrap": 31,
|
|
3478
3480
|
"herdr-fresh-call": 38,
|
|
3479
3481
|
"herdr-supply": 11,
|
|
@@ -3497,13 +3499,13 @@ let manifestCount: number;
|
|
|
3497
3499
|
"release-gate": 24,
|
|
3498
3500
|
"retired-sent-surface": 2,
|
|
3499
3501
|
"resume-args": 6,
|
|
3500
|
-
"resume-launch-identity":
|
|
3502
|
+
"resume-launch-identity": 7,
|
|
3501
3503
|
"self-address": 8,
|
|
3502
3504
|
"setup-verdict": 14,
|
|
3503
3505
|
"source-install": 2,
|
|
3504
3506
|
"typing-call-fence": 1,
|
|
3505
3507
|
"v2-surface": 13,
|
|
3506
|
-
"v2-visible-resume":
|
|
3508
|
+
"v2-visible-resume": 18,
|
|
3507
3509
|
};
|
|
3508
3510
|
const laneTally: Record<string, number> = {};
|
|
3509
3511
|
for (const man of manifests) laneTally[man.lane] = (laneTally[man.lane] ?? 0) + man.mutants.length;
|
|
@@ -174,7 +174,7 @@ function makeRecordingConnection(calls: RecordedCall[]): AcpConnectionLike {
|
|
|
174
174
|
},
|
|
175
175
|
setSessionConfigOption: async (params) => {
|
|
176
176
|
calls.push({ method: "setSessionConfigOption", params });
|
|
177
|
-
return {};
|
|
177
|
+
return { configOptions: [{ id: "model", currentValue: (params as { value?: unknown }).value }] };
|
|
178
178
|
},
|
|
179
179
|
prompt: async (params) => {
|
|
180
180
|
calls.push({ method: "prompt", params });
|
|
@@ -381,12 +381,19 @@ function makeRecordingConnection(calls: RecordedCall[]): AcpConnectionLike {
|
|
|
381
381
|
"backend.ts still sends the clientInfo the probe mirrors",
|
|
382
382
|
);
|
|
383
383
|
// The claude adapter's enforceModel wire shape — the LIVE probe executes THIS
|
|
384
|
-
// method (emitted twin), so its shape is pinned where it lives.
|
|
384
|
+
// method (emitted twin), so its shape is pinned where it lives. Sliced to the claude
|
|
385
|
+
// adapter: the cortex adapter makes the same call, and must not satisfy this pin.
|
|
386
|
+
const claudeAdapterSrc = ADAPTER_SRC.slice(
|
|
387
|
+
ADAPTER_SRC.indexOf("export const claudeAdapter"),
|
|
388
|
+
ADAPTER_SRC.indexOf("export const cortexAdapter"),
|
|
389
|
+
);
|
|
385
390
|
assert.ok(
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
391
|
+
claudeAdapterSrc.length > 0 &&
|
|
392
|
+
claudeAdapterSrc.includes(
|
|
393
|
+
'await setConfig.call(connection, {\n\t\t\tsessionId: acpSessionId,\n\t\t\tconfigId: "model",\n\t\t\tvalue: nativeModelId,\n\t\t});',
|
|
394
|
+
) &&
|
|
395
|
+
claudeAdapterSrc.includes("confirmClaudeSetModelAnswer(answer, nativeModelId);"),
|
|
396
|
+
'claudeAdapter.enforceModel still sends setSessionConfigOption({configId:"model"}) and reads its answer back',
|
|
390
397
|
);
|
|
391
398
|
|
|
392
399
|
// Permission policy: the runner's copy must mirror backend.ts's private
|
|
@@ -42,6 +42,7 @@ import assert from "node:assert/strict";
|
|
|
42
42
|
import * as fs from "node:fs";
|
|
43
43
|
import * as os from "node:os";
|
|
44
44
|
import * as path from "node:path";
|
|
45
|
+
import { AcpModelNotCuratedError } from "../pi-extensions/lib/acp/model-ids.js";
|
|
45
46
|
import { serializeMetaIdentity, upsertMetaSession } from "../pi-extensions/lib/meta-session.ts";
|
|
46
47
|
import {
|
|
47
48
|
ResumeBackendUnsupportedError,
|
|
@@ -162,6 +163,43 @@ function main(): void {
|
|
|
162
163
|
);
|
|
163
164
|
}
|
|
164
165
|
|
|
166
|
+
// 4d. #128 — the second EXPECTED refusal. Under the `entwurf` provider Pi resolves `--model`
|
|
167
|
+
// by substring, so a retired Claude 5 id would reopen on a Cortex row. The pair judged is the
|
|
168
|
+
// one the launch would EMIT: a bare Claude id recorded under another provider is routed to
|
|
169
|
+
// `entwurf` too, so judging the recorded provider alone would let that one through.
|
|
170
|
+
{
|
|
171
|
+
const acpModelLine = (provider: string, modelId: string): string =>
|
|
172
|
+
`${JSON.stringify({ type: "model_change", provider, modelId })}\n`;
|
|
173
|
+
const settle = (gid: string): { identity?: ReturnType<typeof resolveResumeLaunchIdentity>; err?: unknown } => {
|
|
174
|
+
try {
|
|
175
|
+
return { identity: resolveResumeLaunchIdentity(gid) };
|
|
176
|
+
} catch (err) {
|
|
177
|
+
return { err };
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
const minted = (native: string, name: string, provider: string, modelId: string): string =>
|
|
181
|
+
mintRecord(native, writeTranscript(name, sessionLine(native) + acpModelLine(provider, modelId)));
|
|
182
|
+
const retired = settle(
|
|
183
|
+
minted("0199a5a5-1111-4222-8333-444455556666", "acp-retired.jsonl", "entwurf", "claude-sonnet-5"),
|
|
184
|
+
);
|
|
185
|
+
const routed = settle(
|
|
186
|
+
minted("0199b5b5-1111-4222-8333-444455556666", "acp-routed.jsonl", "anthropic", "claude-opus-5"),
|
|
187
|
+
);
|
|
188
|
+
const current = settle(
|
|
189
|
+
minted("0199c5c5-1111-4222-8333-444455556666", "acp-current.jsonl", "entwurf", "claude-sonnet-5-5"),
|
|
190
|
+
);
|
|
191
|
+
ok(
|
|
192
|
+
"4d: an entwurf-provider resume of a non-curated id is a TYPED refusal — recorded under entwurf, or a bare Claude id the launch would route to entwurf — while the exact 5.5 id resolves unchanged [QK:RESUME-ID-ACP-EXACT-CURATION]",
|
|
193
|
+
retired.err instanceof AcpModelNotCuratedError &&
|
|
194
|
+
retired.err.reason === "acp-model-not-curated" &&
|
|
195
|
+
retired.err.model === "claude-sonnet-5" &&
|
|
196
|
+
routed.err instanceof AcpModelNotCuratedError &&
|
|
197
|
+
routed.err.model === "claude-opus-5" &&
|
|
198
|
+
current.identity?.provider === "entwurf" &&
|
|
199
|
+
current.identity.model === "claude-sonnet-5-5",
|
|
200
|
+
);
|
|
201
|
+
}
|
|
202
|
+
|
|
165
203
|
const gidNoFile = mintRecord("0199dddd-1111-4222-8333-444455556666", null);
|
|
166
204
|
rejects(gidNoFile, "no recorded transcriptPath", "4: transcriptPath null → nothing to resume");
|
|
167
205
|
|
|
@@ -5,21 +5,21 @@
|
|
|
5
5
|
{
|
|
6
6
|
"claim": "CORTEX-CURATED-FOUR-ROWS",
|
|
7
7
|
"title": "dropping a curated row silently shrinks the GLG-decided 4-row cortex surface",
|
|
8
|
-
"subject": "pi-extensions/lib/acp/
|
|
8
|
+
"subject": "pi-extensions/lib/acp/model-ids.js",
|
|
9
9
|
"find": [
|
|
10
|
-
"export const SUPPORTED_CORTEX_MODEL_IDS = [",
|
|
10
|
+
"export const SUPPORTED_CORTEX_MODEL_IDS = /** @type {const} */ ([",
|
|
11
11
|
"\t\"cortex-auto\",",
|
|
12
12
|
"\t\"cortex-claude-opus-5\",",
|
|
13
13
|
"\t\"cortex-claude-sonnet-5\",",
|
|
14
14
|
"\t\"cortex-openai-gpt-5.4\",",
|
|
15
|
-
"]
|
|
15
|
+
"]);"
|
|
16
16
|
],
|
|
17
17
|
"replace": [
|
|
18
|
-
"export const SUPPORTED_CORTEX_MODEL_IDS = [",
|
|
18
|
+
"export const SUPPORTED_CORTEX_MODEL_IDS = /** @type {const} */ ([",
|
|
19
19
|
"\t\"cortex-auto\",",
|
|
20
20
|
"\t\"cortex-claude-sonnet-5\",",
|
|
21
21
|
"\t\"cortex-openai-gpt-5.4\",",
|
|
22
|
-
"]
|
|
22
|
+
"]);"
|
|
23
23
|
],
|
|
24
24
|
"gate": ["bash", "run.sh", "check-acp-cortex"],
|
|
25
25
|
"timeoutSeconds": 300,
|
|
@@ -29,11 +29,20 @@
|
|
|
29
29
|
{
|
|
30
30
|
"claim": "CLAUDE-CURATED-THREE-ROWS",
|
|
31
31
|
"title": "dropping a curated CLAUDE row shrinks the operator's model list while the exact-set comparison stays green — expected derives from the same constant, so only the independent count catches it",
|
|
32
|
-
"subject": "pi-extensions/lib/acp/
|
|
32
|
+
"subject": "pi-extensions/lib/acp/model-ids.js",
|
|
33
33
|
"find": [
|
|
34
|
-
"export const SUPPORTED_ANTHROPIC_MODEL_IDS =
|
|
34
|
+
"export const SUPPORTED_ANTHROPIC_MODEL_IDS = /** @type {const} */ ([",
|
|
35
|
+
"\t\"claude-sonnet-5-5\",",
|
|
36
|
+
"\t\"claude-opus-5-5\",",
|
|
37
|
+
"\t\"claude-fable-5-1\",",
|
|
38
|
+
"]);"
|
|
39
|
+
],
|
|
40
|
+
"replace": [
|
|
41
|
+
"export const SUPPORTED_ANTHROPIC_MODEL_IDS = /** @type {const} */ ([",
|
|
42
|
+
"\t\"claude-sonnet-5-5\",",
|
|
43
|
+
"\t\"claude-opus-5-5\",",
|
|
44
|
+
"]);"
|
|
35
45
|
],
|
|
36
|
-
"replace": ["export const SUPPORTED_ANTHROPIC_MODEL_IDS = [\"claude-sonnet-5\", \"claude-opus-5\"] as const;"],
|
|
37
46
|
"gate": ["bash", "run.sh", "check-acp-provider-surface"],
|
|
38
47
|
"timeoutSeconds": 300,
|
|
39
48
|
"signature": "[QK:CLAUDE-CURATED-THREE-ROWS]",
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "acp-set-model-readback",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "ACP-CLAUDE-SET-MODEL-READBACK",
|
|
7
|
+
"title": "the claude set-model answer is no longer read back — a missing model option or another row reaches the prompt, so a different model answers under the requested id",
|
|
8
|
+
"subject": "pi-extensions/lib/acp/backend-adapter.ts",
|
|
9
|
+
"find": ["\t\tconfirmClaudeSetModelAnswer(answer, nativeModelId);"],
|
|
10
|
+
"replace": ["\t\tvoid answer;"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-acp-set-model-readback"],
|
|
12
|
+
"timeoutSeconds": 60,
|
|
13
|
+
"signature": "[QK:ACP-CLAUDE-SET-MODEL-READBACK]",
|
|
14
|
+
"signatureSource": "pi-extensions/lib/acp/backend-adapter.test.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "ACP-CLAUDE-SET-MODEL-ALIAS-EXACT",
|
|
18
|
+
"title": "an alias answer is matched by row name alone — the `default` row or a retired id's row carrying the 5.5 name answers silently under the 5.5 id",
|
|
19
|
+
"subject": "pi-extensions/lib/acp/backend-adapter.ts",
|
|
20
|
+
"find": ["\tif (alias !== undefined && currentValue === alias.value && selected?.name === alias.name) return;"],
|
|
21
|
+
"replace": ["\tif (alias !== undefined && selected?.name === alias.name) return;"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-acp-set-model-readback"],
|
|
23
|
+
"timeoutSeconds": 60,
|
|
24
|
+
"signature": "[QK:ACP-CLAUDE-SET-MODEL-ALIAS-EXACT]",
|
|
25
|
+
"signatureSource": "pi-extensions/lib/acp/backend-adapter.test.ts"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -138,6 +138,17 @@
|
|
|
138
138
|
"timeoutSeconds": 120,
|
|
139
139
|
"signature": "[QK:FCD-NO-SYNC-SPAWN]",
|
|
140
140
|
"signatureSource": "scripts/check-fresh-call-dispatch.ts"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"claim": "FCD-ACP-MODEL-EXACT",
|
|
144
|
+
"title": "dropping the exact-curation check lets a retired entwurf/claude-sonnet-5 reach a rail, where Pi opens it on the Cortex row by substring",
|
|
145
|
+
"subject": "pi-extensions/lib/fresh-call-dispatch.ts",
|
|
146
|
+
"find": ["\treturn !isCuratedAcpModelId(trimmed.slice(slash + 1));"],
|
|
147
|
+
"replace": ["\treturn false;"],
|
|
148
|
+
"gate": ["bash", "run.sh", "check-fresh-call-dispatch"],
|
|
149
|
+
"timeoutSeconds": 120,
|
|
150
|
+
"signature": "[QK:FCD-ACP-MODEL-EXACT]",
|
|
151
|
+
"signatureSource": "scripts/check-fresh-call-dispatch.ts"
|
|
141
152
|
}
|
|
142
153
|
]
|
|
143
154
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "herdr-dev-checkout",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "DEV-MENU-EXPLICIT-CONFIRM",
|
|
7
|
+
"title": "the source menu invokes apply after an unconfirmed selection instead of requiring exact DEV; the existing helper guards do not substitute for the operator's choice",
|
|
8
|
+
"subject": "run.sh",
|
|
9
|
+
"find": [" if [ \"$confirm\" != DEV ]; then"],
|
|
10
|
+
"replace": [" if false; then"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
12
|
+
"timeoutSeconds": 600,
|
|
13
|
+
"signature": "[QK:DEV-MENU-EXPLICIT-CONFIRM]",
|
|
14
|
+
"signatureSource": "plugins/herdr/use-dev-checkout.test.mjs",
|
|
15
|
+
"build": {
|
|
16
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
17
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"claim": "HERDR-DEV-PREPARE-BEFORE-TEARDOWN",
|
|
22
|
+
"title": "deactivation must be preceded by a successful source bridge proof, not merely a build",
|
|
23
|
+
"subject": "plugins/herdr/use-dev-checkout.sh",
|
|
24
|
+
"find": ["(cd \"$ROOT\" && pnpm run build-bridge)", "\"$ROOT/run.sh\" check-bridge"],
|
|
25
|
+
"replace": ["(cd \"$ROOT\" && pnpm run build-bridge)", ":"],
|
|
26
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
27
|
+
"timeoutSeconds": 600,
|
|
28
|
+
"signatureSource": "plugins/herdr/use-dev-checkout.test.mjs",
|
|
29
|
+
"build": {
|
|
30
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
31
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
32
|
+
},
|
|
33
|
+
"signature": "[QK:HERDR-DEV-PREPARE-BEFORE-TEARDOWN]"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"claim": "HERDR-DEV-RECHECK-BEFORE-TEARDOWN",
|
|
37
|
+
"title": "an old-runtime process appearing during source preparation must refuse before the owner is deactivated",
|
|
38
|
+
"subject": "plugins/herdr/use-dev-checkout.sh",
|
|
39
|
+
"find": ["quiescent", "", "stage=owned-deactivate"],
|
|
40
|
+
"replace": [":", "", "stage=owned-deactivate"],
|
|
41
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
42
|
+
"timeoutSeconds": 600,
|
|
43
|
+
"signatureSource": "plugins/herdr/use-dev-checkout.test.mjs",
|
|
44
|
+
"build": {
|
|
45
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
46
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
47
|
+
},
|
|
48
|
+
"signature": "[QK:HERDR-DEV-RECHECK-BEFORE-TEARDOWN]"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"claim": "HERDR-DEV-NO-SUCCESS-ON-DRIFT",
|
|
52
|
+
"title": "actual Pi model-id drift must remain non-green rather than claiming successful developer wiring",
|
|
53
|
+
"subject": "plugins/herdr/use-dev-checkout.sh",
|
|
54
|
+
"find": [
|
|
55
|
+
"[ \"$ACTUAL_IDS\" = \"$SOURCE_IDS\" ] || { echo '[use-dev-checkout] actual Pi model IDs differ from the explicit checkout provider; not accepted.' >&2; exit 1; }"
|
|
56
|
+
],
|
|
57
|
+
"replace": [
|
|
58
|
+
"true || { echo '[use-dev-checkout] actual Pi model IDs differ from the explicit checkout provider; not accepted.' >&2; exit 1; }"
|
|
59
|
+
],
|
|
60
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
61
|
+
"timeoutSeconds": 600,
|
|
62
|
+
"signatureSource": "plugins/herdr/use-dev-checkout.test.mjs",
|
|
63
|
+
"build": {
|
|
64
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
65
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
66
|
+
},
|
|
67
|
+
"signature": "[QK:HERDR-DEV-NO-SUCCESS-ON-DRIFT]"
|
|
68
|
+
}
|
|
69
|
+
]
|
|
70
|
+
}
|
|
@@ -277,6 +277,123 @@
|
|
|
277
277
|
"output": "mcp/entwurf-bridge/dist"
|
|
278
278
|
}
|
|
279
279
|
},
|
|
280
|
+
{
|
|
281
|
+
"claim": "PI-DURABLE-RECEIVER-READ-WITHDRAWS-STALE",
|
|
282
|
+
"title": "an inbox read no longer withdraws the notices its drain made stale, so each still-queued notice is placed later as its own run and an empty read (#140)",
|
|
283
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
284
|
+
"find": ["\t\t\t\tawait withdrawDrained(context);\n"],
|
|
285
|
+
"replace": [""],
|
|
286
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
287
|
+
"timeoutSeconds": 300,
|
|
288
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-READ-WITHDRAWS-STALE]",
|
|
289
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
290
|
+
"build": {
|
|
291
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
292
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
293
|
+
}
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
"claim": "PI-DURABLE-RECEIVER-FOREIGN-GARDEN-READ-KEEPS",
|
|
297
|
+
"title": "the per-notice file predicate is bypassed, so any read — another garden's included — withdraws notices whose own mail is still unread, and that mail is never announced again",
|
|
298
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
299
|
+
"find": ["\t\t\tif (notice.fresh.some((name) => unread.has(`${name}.delivered`))) continue;\n"],
|
|
300
|
+
"replace": [""],
|
|
301
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
302
|
+
"timeoutSeconds": 300,
|
|
303
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-FOREIGN-GARDEN-READ-KEEPS]",
|
|
304
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
305
|
+
"build": {
|
|
306
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
307
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
"claim": "PI-DURABLE-RECEIVER-PARTIAL-DRAIN-WITHDRAWS-ONLY-ARCHIVED",
|
|
312
|
+
"title": "the withdrawal runs only after a successful read, so a drain that failed part-way leaves the notices of the mail it already archived queued, stale",
|
|
313
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
314
|
+
"find": [
|
|
315
|
+
"\t\t\treturn await call();\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tawait withdrawDrained(context);\n\t\t\t} finally {\n\t\t\t\tleaveGate();\n\t\t\t}\n\t\t}\n"
|
|
316
|
+
],
|
|
317
|
+
"replace": [
|
|
318
|
+
"\t\t\tconst answered = await call();\n\t\t\tif (!answered.isError) await withdrawDrained(context);\n\t\t\treturn answered;\n\t\t} finally {\n\t\t\tleaveGate();\n\t\t}\n"
|
|
319
|
+
],
|
|
320
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
321
|
+
"timeoutSeconds": 300,
|
|
322
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-PARTIAL-DRAIN-WITHDRAWS-ONLY-ARCHIVED]",
|
|
323
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
324
|
+
"build": {
|
|
325
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
326
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
327
|
+
}
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
"claim": "PI-DURABLE-RECEIVER-READ-SERIALIZED",
|
|
331
|
+
"title": "an inbox read no longer waits for the doorbell's gate, so a drain that overtakes an admission in flight withdraws before that notice's handle exists and the notice stays queued, stale",
|
|
332
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
333
|
+
"find": ["\t\tawait enterGate();\n"],
|
|
334
|
+
"replace": [""],
|
|
335
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
336
|
+
"timeoutSeconds": 300,
|
|
337
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-READ-SERIALIZED]",
|
|
338
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
339
|
+
"build": {
|
|
340
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
341
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
342
|
+
}
|
|
343
|
+
},
|
|
344
|
+
{
|
|
345
|
+
"claim": "PI-DURABLE-RECEIVER-ARRIVAL-DURING-READ-ANNOUNCED",
|
|
346
|
+
"title": "the gate opening after a read forgets the signal that landed while it was held, so mail that arrived after the drain is never announced until another arrival",
|
|
347
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
348
|
+
"find": ["\t\tif (pending) void ring(\"signal\");\n"],
|
|
349
|
+
"replace": [""],
|
|
350
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
351
|
+
"timeoutSeconds": 300,
|
|
352
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-ARRIVAL-DURING-READ-ANNOUNCED]",
|
|
353
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
354
|
+
"build": {
|
|
355
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
356
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
357
|
+
}
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"claim": "PI-DURABLE-RECEIVER-WITHDRAW-FAILURE-KEEPS-READ",
|
|
361
|
+
"title": "a notice whose native withdraw rejected is put back among the held ones, so every later read retries that withdraw and names the same failure again",
|
|
362
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
363
|
+
"find": [
|
|
364
|
+
"\t\t\t\tnoteWithdrawalFailure({ reason: \"abort-failed\", requestId: notice.requestId, detail: describeError(error) });\n"
|
|
365
|
+
],
|
|
366
|
+
"replace": [
|
|
367
|
+
"\t\t\t\tnoteWithdrawalFailure({ reason: \"abort-failed\", requestId: notice.requestId, detail: describeError(error) });\n\t\t\t\tnotices.push(notice);\n"
|
|
368
|
+
],
|
|
369
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
370
|
+
"timeoutSeconds": 300,
|
|
371
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-WITHDRAW-FAILURE-KEEPS-READ]",
|
|
372
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
373
|
+
"build": {
|
|
374
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
375
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
{
|
|
379
|
+
"claim": "PI-DURABLE-RECEIVER-INSPECTION-FAILURE-KEEPS-NOTICES",
|
|
380
|
+
"title": "a mailbox that could not be listed is judged as if it held no unread mail, so every held notice is withdrawn while its mail may still be unread",
|
|
381
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
382
|
+
"find": [
|
|
383
|
+
"\t\t\tnoteWithdrawalFailure({ reason: \"inspection-failed\", detail: `${inbox}: ${describeError(error)}` });\n\t\t\treturn;\n"
|
|
384
|
+
],
|
|
385
|
+
"replace": [
|
|
386
|
+
"\t\t\tnoteWithdrawalFailure({ reason: \"inspection-failed\", detail: `${inbox}: ${describeError(error)}` });\n\t\t\tunread = new Set();\n"
|
|
387
|
+
],
|
|
388
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
389
|
+
"timeoutSeconds": 300,
|
|
390
|
+
"signature": "[QK:PI-DURABLE-RECEIVER-INSPECTION-FAILURE-KEEPS-NOTICES]",
|
|
391
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
392
|
+
"build": {
|
|
393
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
394
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
395
|
+
}
|
|
396
|
+
},
|
|
280
397
|
{
|
|
281
398
|
"claim": "PI-DURABLE-CARRIER-RELOCATION-TWO-RULES",
|
|
282
399
|
"title": "a carrier file's import of a sibling keeps its .ts specifier, so the installed carrier asks Node for a file that was never emitted",
|
|
@@ -91,6 +91,21 @@
|
|
|
91
91
|
"timeoutSeconds": 60,
|
|
92
92
|
"signature": "[QK:RESUME-ID-SESSION-ABSOLUTE]",
|
|
93
93
|
"signatureSource": "scripts/check-resume-launch-identity.ts"
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"claim": "RESUME-ID-ACP-EXACT-CURATION",
|
|
97
|
+
"title": "judging the RECORDED provider instead of the emitted one lets a bare Claude 5 id recorded under another provider reopen under entwurf on a Cortex row",
|
|
98
|
+
"subject": "pi-extensions/lib/resume-launch-identity.ts",
|
|
99
|
+
"find": [
|
|
100
|
+
"\tif (provider === PROVIDER_ID && !isCuratedAcpModelId(model)) throw new AcpModelNotCuratedError(model);"
|
|
101
|
+
],
|
|
102
|
+
"replace": [
|
|
103
|
+
"\tif (identity.provider === PROVIDER_ID && !isCuratedAcpModelId(model)) throw new AcpModelNotCuratedError(model);"
|
|
104
|
+
],
|
|
105
|
+
"gate": ["bash", "run.sh", "check-resume-launch-identity"],
|
|
106
|
+
"timeoutSeconds": 60,
|
|
107
|
+
"signature": "[QK:RESUME-ID-ACP-EXACT-CURATION]",
|
|
108
|
+
"signatureSource": "scripts/check-resume-launch-identity.ts"
|
|
94
109
|
}
|
|
95
110
|
]
|
|
96
111
|
}
|
|
@@ -210,6 +210,17 @@
|
|
|
210
210
|
"timeoutSeconds": 60,
|
|
211
211
|
"signature": "[QK:V2RESUME-SHARED-ID-GRAMMAR]",
|
|
212
212
|
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
"claim": "V2RESUME-ACP-MODEL-REFUSED",
|
|
216
|
+
"title": "not matching AcpModelNotCuratedError turns the named refusal into a raw error escaping the resume verb",
|
|
217
|
+
"subject": "pi-extensions/lib/entwurf-v2-visible-resume.ts",
|
|
218
|
+
"find": ["\t\t\tif (err instanceof AcpModelNotCuratedError) {"],
|
|
219
|
+
"replace": ["\t\t\tif (err instanceof AcpModelNotCuratedError && false) {"],
|
|
220
|
+
"gate": ["bash", "run.sh", "check-entwurf-v2-visible-resume"],
|
|
221
|
+
"timeoutSeconds": 60,
|
|
222
|
+
"signature": "[QK:V2RESUME-ACP-MODEL-REFUSED]",
|
|
223
|
+
"signatureSource": "pi-extensions/lib/entwurf-v2-visible-resume.test.ts"
|
|
213
224
|
}
|
|
214
225
|
]
|
|
215
226
|
}
|