@junghanacs/entwurf 0.39.0 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +4 -2
- package/BASELINE.md +60 -5
- package/CHANGELOG.md +557 -0
- package/CONTRIBUTING.md +1 -1
- package/DELIVERY.md +52 -2
- package/FAQ.md +8 -4
- package/README.md +37 -17
- package/VERIFY.md +23 -10
- package/docs/acp-backend-rail.md +5 -1
- package/docs/external-mcp-host.md +8 -6
- package/docs/fresh-cut-policy.md +9 -1
- package/docs/setup-clean-host.md +64 -9
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +100 -24
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-request.js +473 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-retire.js +125 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire-production.js +149 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire.js +158 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +2 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +283 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +7 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -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 +10 -4
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +96 -16
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +5 -29
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +28 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +26 -11
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-retire-request.js +76 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-receive.js +123 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-send.js +259 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/remote-pair-transport.js +80 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +67 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/retirement-event.js +211 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +124 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +53 -2
- package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
- package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +1 -0
- package/mcp/entwurf-bridge/dist/scripts/remote-pair-receive.js +65 -0
- package/mcp/entwurf-bridge/src/index.ts +118 -24
- package/mcp/entwurf-bridge/test.sh +2 -2
- package/mcp/entwurf-bridge/tsconfig.build.json +17 -1
- package/package.json +5 -5
- package/pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh +3 -3
- package/pi-extensions/entwurf-control.ts +55 -20
- package/pi-extensions/lib/cc-retire-pidfd.py +236 -0
- package/pi-extensions/lib/cc-retire-request.ts +553 -0
- package/pi-extensions/lib/control-retire.ts +195 -0
- package/pi-extensions/lib/entwurf-control-rpc.ts +17 -1
- package/pi-extensions/lib/entwurf-v2-retire-production.ts +227 -0
- package/pi-extensions/lib/entwurf-v2-retire.ts +269 -0
- package/pi-extensions/lib/entwurf-v2-surface.ts +2 -1
- package/pi-extensions/lib/entwurf-v2-visible-resume.ts +390 -36
- package/pi-extensions/lib/fresh-call-composition.ts +15 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +45 -4
- package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
- package/pi-extensions/lib/meta-mailbox-body.ts +13 -4
- package/pi-extensions/lib/meta-session.ts +140 -16
- package/pi-extensions/lib/mux-fresh-call.ts +7 -27
- package/pi-extensions/lib/mux-launch.ts +29 -0
- package/pi-extensions/lib/mux-resume-call.ts +33 -12
- package/pi-extensions/lib/pi-retire-request.ts +111 -0
- package/pi-extensions/lib/remote-pair-receive.ts +184 -0
- package/pi-extensions/lib/remote-pair-send.ts +325 -0
- package/pi-extensions/lib/remote-pair-transport.ts +81 -0
- package/pi-extensions/lib/resume-launch-identity.ts +104 -18
- package/pi-extensions/lib/retirement-event.ts +253 -0
- package/pi-extensions/meta-bridge-hook.ts +142 -13
- package/pi-extensions/meta-bridge-pi-durable.ts +56 -2
- package/run.sh +122 -7
- package/scripts/agy-bridge-config.py +4 -1
- package/scripts/build-bridge.sh +14 -0
- package/scripts/check-capability-bundle-reach.ts +135 -2
- package/scripts/check-entwurf-bridge-boot.ts +2 -1
- package/scripts/check-entwurf-fact-provider.ts +1 -0
- package/scripts/check-entwurf-v2-production.ts +2 -0
- package/scripts/check-entwurf-v2-surface.ts +7 -0
- package/scripts/check-gate-qualification.ts +20 -8
- package/scripts/check-herdr-activation.ts +2 -2
- package/scripts/check-herdr-placement.ts +1 -0
- package/scripts/check-hook-launch-topology.ts +6 -15
- package/scripts/check-install-container.sh +2 -2
- package/scripts/check-meta-doctor-oracle.sh +27 -1
- package/scripts/check-meta-facts.ts +8 -3
- package/scripts/check-meta-hook-session-switch.ts +230 -13
- package/scripts/check-meta-identity-consumers.ts +1 -0
- package/scripts/check-meta-listing.ts +1 -0
- package/scripts/check-meta-manifest-schema.py +1 -1
- package/scripts/check-meta-session.ts +31 -0
- package/scripts/check-meta-v3-record.ts +55 -1
- package/scripts/check-mux-resume-call.ts +35 -9
- package/scripts/check-peer-facts.ts +1 -0
- package/scripts/check-pi-durable-contact.ts +3 -1
- package/scripts/check-pi-durable-send.ts +4 -2
- package/scripts/check-pi-mcp-bridge.ts +1 -0
- package/scripts/check-remote-pair-installed.ts +242 -0
- package/scripts/check-resume-launch-identity.ts +62 -23
- package/scripts/lib/meta-hook-bundle.ts +72 -0
- package/scripts/lib/remote-pair-installed-audit.ts +25 -0
- package/scripts/meta-bridge-claude-floor.sh +13 -9
- package/scripts/meta-bridge-doctor.sh +17 -0
- package/scripts/meta-bridge-install.sh +6 -0
- package/scripts/meta-facts.ts +1 -1
- package/scripts/mutants/bridge-boot-resume.json +5 -2
- package/scripts/mutants/cc-retire-pidfd.json +129 -0
- package/scripts/mutants/cc-retire-request.json +171 -0
- package/scripts/mutants/control-retire.json +105 -0
- package/scripts/mutants/control-send-receipt.json +2 -2
- package/scripts/mutants/copilot-receive.json +2 -6
- package/scripts/mutants/entwurf-v2-retire.json +476 -0
- package/scripts/mutants/fresh-call-dispatch.json +37 -0
- package/scripts/mutants/meta-hook-session-switch.json +88 -0
- package/scripts/mutants/meta-identity.json +57 -0
- package/scripts/mutants/mux-fresh-call.json +1 -1
- package/scripts/mutants/mux-resume-call.json +40 -4
- package/scripts/mutants/pi-durable.json +79 -0
- package/scripts/mutants/pi-retire-request.json +72 -0
- package/scripts/mutants/remote-pair-display.json +53 -0
- package/scripts/mutants/remote-pair-installed-audit.json +28 -0
- package/scripts/mutants/remote-pair-receive.json +126 -0
- package/scripts/mutants/remote-pair-roundtrip.json +83 -0
- package/scripts/mutants/remote-pair-send.json +194 -0
- package/scripts/mutants/remote-pair-transport.json +66 -0
- package/scripts/mutants/resume-launch-identity.json +35 -8
- package/scripts/mutants/retirement-event.json +195 -0
- package/scripts/mutants/v2-surface.json +16 -0
- package/scripts/mutants/v2-visible-resume.json +283 -13
- package/scripts/probe-bridge-command.ts +1 -0
- package/scripts/remote-pair-receive.ts +73 -0
- package/scripts/smoke-agy-install-state.sh +2 -2
- package/scripts/smoke-copilot-mcp-state.sh +1 -1
- package/scripts/smoke-herdr-raw-install-live.sh +5 -4
- package/scripts/smoke-meta-install-state.sh +4 -4
- package/scripts/smoke-mux-lifecycle-live.ts +10 -10
- package/scripts/smoke-omp-mcp-state.sh +1 -1
- package/scripts/smoke-pi-durable-fresh-live.ts +5 -3
- package/scripts/smoke-pi-provider-state.sh +3 -3
|
@@ -48,6 +48,63 @@
|
|
|
48
48
|
"timeoutSeconds": 120,
|
|
49
49
|
"signature": "[QK:META-CREATE-PUBLISHED-CLEANUP]",
|
|
50
50
|
"signatureSource": "scripts/check-meta-session.ts"
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"claim": "META-V3-INCARNATION-ABSENT-NULL",
|
|
54
|
+
"title": "a V3 body without attachIncarnation is refused, so every untouched record becomes unreadable",
|
|
55
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
56
|
+
"find": [
|
|
57
|
+
"\t\tattachIncarnation: requireAttachIncarnation(obj.attachIncarnation === undefined ? null : obj.attachIncarnation),"
|
|
58
|
+
],
|
|
59
|
+
"replace": ["\t\tattachIncarnation: requireAttachIncarnation(obj.attachIncarnation),"],
|
|
60
|
+
"gate": ["bash", "run.sh", "check-meta-v3-record"],
|
|
61
|
+
"timeoutSeconds": 120,
|
|
62
|
+
"signature": "[QK:META-V3-INCARNATION-ABSENT-NULL]",
|
|
63
|
+
"signatureSource": "scripts/check-meta-v3-record.ts"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"claim": "META-V3-INCARNATION-MALFORMED",
|
|
67
|
+
"title": "any string is accepted as a binding",
|
|
68
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
69
|
+
"find": ["\tif (typeof value !== \"string\" || !ATTACH_INCARNATION_RE.test(value)) {"],
|
|
70
|
+
"replace": ["\tif (typeof value !== \"string\") {"],
|
|
71
|
+
"gate": ["bash", "run.sh", "check-meta-v3-record"],
|
|
72
|
+
"timeoutSeconds": 120,
|
|
73
|
+
"signature": "[QK:META-V3-INCARNATION-MALFORMED]",
|
|
74
|
+
"signatureSource": "scripts/check-meta-v3-record.ts"
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
"claim": "META-V3-INCARNATION-ALWAYS-EMITTED",
|
|
78
|
+
"title": "the serializer drops attachIncarnation, so a committed binding never reaches disk",
|
|
79
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
80
|
+
"find": ["\t\tattachIncarnation: identity.attachIncarnation,"],
|
|
81
|
+
"replace": [""],
|
|
82
|
+
"gate": ["bash", "run.sh", "check-meta-v3-record"],
|
|
83
|
+
"timeoutSeconds": 120,
|
|
84
|
+
"signature": "[QK:META-V3-INCARNATION-ALWAYS-EMITTED]",
|
|
85
|
+
"signatureSource": "scripts/check-meta-v3-record.ts"
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
"claim": "META-UPSERT-PRESERVES-INCARNATION",
|
|
89
|
+
"title": "an attach that does not mint clears the binding",
|
|
90
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
91
|
+
"find": ["\t\t\t? existing.attachIncarnation"],
|
|
92
|
+
"replace": ["\t\t\t? null"],
|
|
93
|
+
"gate": ["bash", "run.sh", "check-meta-v3-record"],
|
|
94
|
+
"timeoutSeconds": 120,
|
|
95
|
+
"signature": "[QK:META-UPSERT-PRESERVES-INCARNATION]",
|
|
96
|
+
"signatureSource": "scripts/check-meta-v3-record.ts"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"claim": "META-UPSERT-EXPECT-ACTION",
|
|
100
|
+
"title": "upsert ignores expectAction, so a raced create silently becomes an unlocked attach",
|
|
101
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
102
|
+
"find": ["\tif (opts.expectAction !== undefined && decision.action !== opts.expectAction) {"],
|
|
103
|
+
"replace": ["\tif (false) {"],
|
|
104
|
+
"gate": ["bash", "run.sh", "check-meta-session"],
|
|
105
|
+
"timeoutSeconds": 120,
|
|
106
|
+
"signature": "[QK:META-UPSERT-EXPECT-ACTION]",
|
|
107
|
+
"signatureSource": "scripts/check-meta-session.ts"
|
|
51
108
|
}
|
|
52
109
|
]
|
|
53
110
|
}
|
|
@@ -151,7 +151,7 @@
|
|
|
151
151
|
"title": "MCP drops the required model field from fresh-call while the composition still expects one",
|
|
152
152
|
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
153
153
|
"find": [
|
|
154
|
-
"\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi, provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name.\",\n\t\t\t),\n"
|
|
154
|
+
"\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi (a bare alias is refused), provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name. Neither pi nor pi-durable may name the openrouter provider.\",\n\t\t\t),\n"
|
|
155
155
|
],
|
|
156
156
|
"replace": [""],
|
|
157
157
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -72,8 +72,11 @@
|
|
|
72
72
|
"claim": "MUXRESUME-NO-IDENTITY",
|
|
73
73
|
"title": "identity vocabulary enters the placement module, which is the first step of a leaf learning whose citizen it is opening",
|
|
74
74
|
"subject": "pi-extensions/lib/mux-resume-call.ts",
|
|
75
|
-
"find": ["export const RESUME_CALL_RUNTIME = \"pi\";"],
|
|
76
|
-
"replace": [
|
|
75
|
+
"find": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;"],
|
|
76
|
+
"replace": [
|
|
77
|
+
"export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;",
|
|
78
|
+
"export const RESUME_CALL_TARGET_KEY = \"gardenId\";"
|
|
79
|
+
],
|
|
77
80
|
"gate": ["bash", "run.sh", "check-mux-resume-call"],
|
|
78
81
|
"timeoutSeconds": 60,
|
|
79
82
|
"signature": "[QK:MUXRESUME-NO-IDENTITY]",
|
|
@@ -97,10 +100,10 @@
|
|
|
97
100
|
"title": "the MCP description drops the dormant-only scope, inviting callers to aim the verb at live citizens it will refuse",
|
|
98
101
|
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
99
102
|
"find": [
|
|
100
|
-
"\t\"Reopen ONE DORMANT pi citizen under its OWN garden id, in a visible window in the operator's
|
|
103
|
+
"\t\"Reopen ONE DORMANT pi or Claude Code citizen under its OWN garden id, in a visible window in the operator's \" +"
|
|
101
104
|
],
|
|
102
105
|
"replace": [
|
|
103
|
-
"\t\"Reopen ONE pi citizen under its OWN garden id, in a visible window in the operator's
|
|
106
|
+
"\t\"Reopen ONE pi or Claude Code citizen under its OWN garden id, in a visible window in the operator's \" +"
|
|
104
107
|
],
|
|
105
108
|
"gate": ["bash", "run.sh", "check-mux-resume-call"],
|
|
106
109
|
"timeoutSeconds": 60,
|
|
@@ -119,6 +122,39 @@
|
|
|
119
122
|
"timeoutSeconds": 60,
|
|
120
123
|
"signature": "[QK:MUXRESUME-MCP-TARGET-PASSTHROUGH]",
|
|
121
124
|
"signatureSource": "scripts/check-mux-resume-call.ts"
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
"claim": "MUXRESUME-RUNTIME-TABLE",
|
|
128
|
+
"title": "a Claude Code resume is started under pi, so the window opens the wrong runtime on the right session id",
|
|
129
|
+
"subject": "pi-extensions/lib/mux-resume-call.ts",
|
|
130
|
+
"find": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;"],
|
|
131
|
+
"replace": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"pi\" } as const;"],
|
|
132
|
+
"gate": ["bash", "run.sh", "check-mux-resume-call"],
|
|
133
|
+
"timeoutSeconds": 60,
|
|
134
|
+
"signature": "[QK:MUXRESUME-RUNTIME-TABLE]",
|
|
135
|
+
"signatureSource": "scripts/check-mux-resume-call.ts"
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"claim": "MUXRESUME-HERDR-REFUSED",
|
|
139
|
+
"title": "inside herdr the tmux resume rail no longer refuses, so an ambient TMUX opens the window where the operator is not looking",
|
|
140
|
+
"subject": "pi-extensions/lib/mux-resume-call.ts",
|
|
141
|
+
"find": ["\tif (env.HERDR_ENV === \"1\") return { ok: false, reason: \"herdr-resume-unsupported\" };"],
|
|
142
|
+
"replace": [""],
|
|
143
|
+
"gate": ["bash", "run.sh", "check-mux-resume-call"],
|
|
144
|
+
"timeoutSeconds": 60,
|
|
145
|
+
"signature": "[QK:MUXRESUME-HERDR-REFUSED]",
|
|
146
|
+
"signatureSource": "scripts/check-mux-resume-call.ts"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"claim": "MUXRESUME-ARGV-IDENTITY-SCRUB",
|
|
150
|
+
"title": "the resume window stops emptying the inherited pi identity carriers, so a resumed Claude Code presents a stale identity to its bridge",
|
|
151
|
+
"subject": "pi-extensions/lib/mux-resume-call.ts",
|
|
152
|
+
"find": ["\t\t...SCRUBBED_INHERITED_ENV.flatMap((assignment) => [\"-e\", assignment]),"],
|
|
153
|
+
"replace": [""],
|
|
154
|
+
"gate": ["bash", "run.sh", "check-mux-resume-call"],
|
|
155
|
+
"timeoutSeconds": 60,
|
|
156
|
+
"signature": "[QK:MUXRESUME-ARGV-IDENTITY-SCRUB]",
|
|
157
|
+
"signatureSource": "scripts/check-mux-resume-call.ts"
|
|
122
158
|
}
|
|
123
159
|
]
|
|
124
160
|
}
|
|
@@ -2,6 +2,61 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"lane": "pi-durable",
|
|
4
4
|
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "PI-DURABLE-RETIRE-CALL",
|
|
7
|
+
"title": "retirement alone drops the actual request cancellation signal",
|
|
8
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
9
|
+
"find": [
|
|
10
|
+
"\t\t\tconst call = () => client.callTool(name, (args ?? {}) as Record<string, unknown>, context?.abortSignal);"
|
|
11
|
+
],
|
|
12
|
+
"replace": [
|
|
13
|
+
"\t\t\tconst call = () => client.callTool(name, (args ?? {}) as Record<string, unknown>, name === \"entwurf_retire_call\" ? undefined : context?.abortSignal);"
|
|
14
|
+
],
|
|
15
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
16
|
+
"timeoutSeconds": 300,
|
|
17
|
+
"signature": "[QK:PI-DURABLE-RETIRE-CALL]",
|
|
18
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
19
|
+
"build": {
|
|
20
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
21
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"claim": "PI-DURABLE-RETIRE-POLICY",
|
|
26
|
+
"title": "the native retirement description treats actor identity as a standing grant",
|
|
27
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
28
|
+
"find": [
|
|
29
|
+
"\t\t\"Only when the human operator explicitly requested this particular target/work: make ONE retirement attempt for that request \" +"
|
|
30
|
+
],
|
|
31
|
+
"replace": [
|
|
32
|
+
"\t\t\"A caller record alone authorizes this target/work: make ONE retirement attempt for that request \" +"
|
|
33
|
+
],
|
|
34
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
35
|
+
"timeoutSeconds": 300,
|
|
36
|
+
"signature": "[QK:PI-DURABLE-RETIRE-POLICY]",
|
|
37
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
38
|
+
"build": {
|
|
39
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
40
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"claim": "PI-DURABLE-RETIRE-CALL-REACHES-BRIDGE",
|
|
45
|
+
"title": "the compiled retirement handler discards the actual host-authoritative caller",
|
|
46
|
+
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
47
|
+
"find": [
|
|
48
|
+
"\t\t\t\t\tresolveCaller: async () => (await resolveAuthoritativeSender({ requestMeta: extra._meta }))?.envelope ?? null,"
|
|
49
|
+
],
|
|
50
|
+
"replace": ["\t\t\t\t\tresolveCaller: async () => null,"],
|
|
51
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
52
|
+
"timeoutSeconds": 300,
|
|
53
|
+
"signature": "[QK:PI-DURABLE-RETIRE-CALL-REACHES-BRIDGE]",
|
|
54
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
55
|
+
"build": {
|
|
56
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
57
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
58
|
+
}
|
|
59
|
+
},
|
|
5
60
|
{
|
|
6
61
|
"claim": "PI-DURABLE-ENTRY-GUARD-FLOOR-SAFE",
|
|
7
62
|
"title": "the verifier's entry guard goes back to import.meta.main, which the floor's runner can misread as the process entry",
|
|
@@ -1223,6 +1278,30 @@
|
|
|
1223
1278
|
"signature": "[QK:PI-DURABLE-RESUME-CANCEL-OPENS-NOTHING]",
|
|
1224
1279
|
"signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
|
|
1225
1280
|
"build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
|
|
1281
|
+
},
|
|
1282
|
+
{
|
|
1283
|
+
"claim": "PI-DURABLE-RESUME-CALL-EXPOSED",
|
|
1284
|
+
"title": "entwurf_resume_call drops out of the durable contact's tools, so the coordinator citizen cannot reopen a dormant pi sibling",
|
|
1285
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
1286
|
+
"find": ["\t\ttools: PI_DURABLE_TOOL_NAMES.map(tool),"],
|
|
1287
|
+
"replace": ["\t\ttools: PI_DURABLE_TOOL_NAMES.filter((name) => name !== \"entwurf_resume_call\").map(tool),"],
|
|
1288
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
1289
|
+
"timeoutSeconds": 300,
|
|
1290
|
+
"signature": "[QK:PI-DURABLE-RESUME-CALL-EXPOSED]",
|
|
1291
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
1292
|
+
"build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
|
|
1293
|
+
},
|
|
1294
|
+
{
|
|
1295
|
+
"claim": "PI-DURABLE-RESUME-CALL-REACHES-BRIDGE",
|
|
1296
|
+
"title": "the production stdio connector stops carrying a tool's arguments: every stub-bridge case still passes, but the real bridge never sees the target the model named",
|
|
1297
|
+
"subject": "pi-extensions/meta-bridge-pi-durable.ts",
|
|
1298
|
+
"find": ["const result = await client.callTool({ name, arguments: args }, undefined, { signal });"],
|
|
1299
|
+
"replace": ["const result = await client.callTool({ name, arguments: {} }, undefined, { signal });"],
|
|
1300
|
+
"gate": ["bash", "run.sh", "check-pi-durable-beside"],
|
|
1301
|
+
"timeoutSeconds": 300,
|
|
1302
|
+
"signature": "[QK:PI-DURABLE-RESUME-CALL-REACHES-BRIDGE]",
|
|
1303
|
+
"signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
|
|
1304
|
+
"build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
|
|
1226
1305
|
}
|
|
1227
1306
|
]
|
|
1228
1307
|
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "pi-retire-request",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "PI-RETIRE-PREFLIGHT",
|
|
7
|
+
"title": "a mismatched native session escapes preflight and sends a retirement RPC",
|
|
8
|
+
"subject": "pi-extensions/lib/pi-retire-request.ts",
|
|
9
|
+
"find": ["\t\ttarget.nativeSessionId !== expected.nativeSessionId ||\n"],
|
|
10
|
+
"replace": [""],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
12
|
+
"timeoutSeconds": 600,
|
|
13
|
+
"signature": "[QK:PI-RETIRE-PREFLIGHT]",
|
|
14
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "PI-RETIRE-WIRE",
|
|
18
|
+
"title": "the one fixed retirement request carries a different native session than the certified record",
|
|
19
|
+
"subject": "pi-extensions/lib/pi-retire-request.ts",
|
|
20
|
+
"find": ["{ type: \"retire\", gardenId: target.gardenId, nativeSessionId: target.nativeSessionId }"],
|
|
21
|
+
"replace": ["{ type: \"retire\", gardenId: target.gardenId, nativeSessionId: \"wrong-native-id\" }"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
23
|
+
"timeoutSeconds": 600,
|
|
24
|
+
"signature": "[QK:PI-RETIRE-WIRE]",
|
|
25
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"claim": "PI-RETIRE-PARSE-CLOSED",
|
|
29
|
+
"title": "a failure response with a requested boundary is incorrectly accepted",
|
|
30
|
+
"subject": "pi-extensions/lib/pi-retire-request.ts",
|
|
31
|
+
"find": ["if (response.success === true && data.boundary === \"shutdown-requested\") {"],
|
|
32
|
+
"replace": ["if (data.boundary === \"shutdown-requested\") {"],
|
|
33
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
34
|
+
"timeoutSeconds": 600,
|
|
35
|
+
"signature": "[QK:PI-RETIRE-PARSE-CLOSED]",
|
|
36
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"claim": "PI-RETIRE-REFUSALS",
|
|
40
|
+
"title": "the known receiver refusal domain is dropped and every named refusal becomes unknown",
|
|
41
|
+
"subject": "pi-extensions/lib/pi-retire-request.ts",
|
|
42
|
+
"find": ["if (data.boundary === \"refused\" && RECEIVER_REFUSALS.includes(data.reason as ReceiverRefusal)) {"],
|
|
43
|
+
"replace": ["if (false) {"],
|
|
44
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
45
|
+
"timeoutSeconds": 600,
|
|
46
|
+
"signature": "[QK:PI-RETIRE-REFUSALS]",
|
|
47
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"claim": "PI-RETIRE-TRANSPORT",
|
|
51
|
+
"title": "a timeout or lost response is misreported as a certain receiver refusal",
|
|
52
|
+
"subject": "pi-extensions/lib/pi-retire-request.ts",
|
|
53
|
+
"find": ["\t\treturn { boundary: \"unknown\", reason: \"transport-error\" };"],
|
|
54
|
+
"replace": ["\t\treturn { boundary: \"refused\", phase: \"receiver\", reason: \"target-closing\" };"],
|
|
55
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
56
|
+
"timeoutSeconds": 600,
|
|
57
|
+
"signature": "[QK:PI-RETIRE-TRANSPORT]",
|
|
58
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"claim": "PI-RETIRE-ENVELOPE",
|
|
62
|
+
"title": "the production receiver drops its error reason so the strict adapter cannot interpret refusals",
|
|
63
|
+
"subject": "pi-extensions/lib/control-retire.ts",
|
|
64
|
+
"find": ["\t\t...(result.boundary !== \"shutdown-requested\" ? { error: result.reason } : {}),\n"],
|
|
65
|
+
"replace": [""],
|
|
66
|
+
"gate": ["bash", "run.sh", "check-pi-retire-request"],
|
|
67
|
+
"timeoutSeconds": 600,
|
|
68
|
+
"signature": "[QK:PI-RETIRE-ENVELOPE]",
|
|
69
|
+
"signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
|
|
70
|
+
}
|
|
71
|
+
]
|
|
72
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "remote-pair-display",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "REMOTE-DISPLAY-LOCAL-UNCHANGED",
|
|
7
|
+
"title": "the remote branch is taken for every non-replyable sender, so an ordinary external or meta-session header turns into a remote line naming a route that does not exist",
|
|
8
|
+
"subject": "pi-extensions/lib/meta-mailbox-body.ts",
|
|
9
|
+
"find": ["\tconst remote = !replyable ? sender.remote : undefined;"],
|
|
10
|
+
"replace": [
|
|
11
|
+
"\tconst remote = !replyable ? (sender.remote ?? { via: \"?\", replyRoute: \"none\" as const }) : undefined;"
|
|
12
|
+
],
|
|
13
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
14
|
+
"timeoutSeconds": 600,
|
|
15
|
+
"signature": "[QK:REMOTE-DISPLAY-LOCAL-UNCHANGED]",
|
|
16
|
+
"signatureSource": "pi-extensions/lib/meta-mailbox-body.test.ts",
|
|
17
|
+
"build": {
|
|
18
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
19
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"claim": "REMOTE-DISPLAY-SESSIONLINE",
|
|
24
|
+
"title": "a remote sender with a declared route back is told to reply via entwurf_v2 as if that route had been probed",
|
|
25
|
+
"subject": "pi-extensions/lib/meta-mailbox-body.ts",
|
|
26
|
+
"find": ["\"reply route declared, not probed\""],
|
|
27
|
+
"replace": ["\"reply via entwurf_v2 to this sessionId\""],
|
|
28
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
29
|
+
"timeoutSeconds": 600,
|
|
30
|
+
"signature": "[QK:REMOTE-DISPLAY-SESSIONLINE]",
|
|
31
|
+
"signatureSource": "pi-extensions/lib/meta-mailbox-body.test.ts",
|
|
32
|
+
"build": {
|
|
33
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
34
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"claim": "REMOTE-DISPLAY-SENDER-HOST-CWD",
|
|
39
|
+
"title": "a remote sender's cwd is abbreviated against this host's HOME, so a path on the other machine reads as a local one",
|
|
40
|
+
"subject": "pi-extensions/lib/meta-mailbox-body.ts",
|
|
41
|
+
"find": ["\tconst where = remote ? `${sender.cwd} (sender-host path)` : abbreviateHome(sender.cwd);"],
|
|
42
|
+
"replace": ["\tconst where = abbreviateHome(sender.cwd);"],
|
|
43
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
44
|
+
"timeoutSeconds": 600,
|
|
45
|
+
"signature": "[QK:REMOTE-DISPLAY-SENDER-HOST-CWD]",
|
|
46
|
+
"signatureSource": "pi-extensions/lib/meta-mailbox-body.test.ts",
|
|
47
|
+
"build": {
|
|
48
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
49
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
]
|
|
53
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "remote-pair-installed-audit",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "RPI-AUDIT-REAL-PATH",
|
|
7
|
+
"title": "the installed-closure audit judges a resolved file by its link path, so an installed file that is a symlink into a checkout passes as inside the consumer",
|
|
8
|
+
"subject": "scripts/lib/remote-pair-installed-audit.ts",
|
|
9
|
+
"find": ["\t\t\tconst real = fs.realpathSync(fileURLToPath(url));"],
|
|
10
|
+
"replace": ["\t\t\tconst real = fileURLToPath(url);"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-remote-pair-installed-audit"],
|
|
12
|
+
"timeoutSeconds": 120,
|
|
13
|
+
"signature": "[QK:RPI-AUDIT-REAL-PATH]",
|
|
14
|
+
"signatureSource": "test/remote-pair-installed-audit.test.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "RPI-AUDIT-ROOT-BOUNDARY",
|
|
18
|
+
"title": "the installed-closure audit treats any path that merely starts with the consumer prefix as inside it, so a sibling directory such as <prefix>-x passes",
|
|
19
|
+
"subject": "scripts/lib/remote-pair-installed-audit.ts",
|
|
20
|
+
"find": ["\t\t\tif (real !== realRoot && !real.startsWith(`${realRoot}${path.sep}`)) out.add(real);"],
|
|
21
|
+
"replace": ["\t\t\tif (real !== realRoot && !real.startsWith(realRoot)) out.add(real);"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-remote-pair-installed-audit"],
|
|
23
|
+
"timeoutSeconds": 120,
|
|
24
|
+
"signature": "[QK:RPI-AUDIT-ROOT-BOUNDARY]",
|
|
25
|
+
"signatureSource": "test/remote-pair-installed-audit.test.ts"
|
|
26
|
+
}
|
|
27
|
+
]
|
|
28
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "remote-pair-receive",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "REMOTE-PAIR-FROM-OUTSIDE-NO-MUTATION",
|
|
7
|
+
"title": "the receiving entry stops checking the claimed sender against the declared pair, so any gid the SSH account writes is dispatched into the declared target's mailbox",
|
|
8
|
+
"subject": "pi-extensions/lib/remote-pair-receive.ts",
|
|
9
|
+
"find": ["\tif (claim.from !== decl.remoteGardenId) {"],
|
|
10
|
+
"replace": ["\tif (false) {"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
12
|
+
"timeoutSeconds": 600,
|
|
13
|
+
"signature": "[QK:REMOTE-PAIR-FROM-OUTSIDE-NO-MUTATION]",
|
|
14
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
15
|
+
"build": {
|
|
16
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
17
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"claim": "REMOTE-PAIR-TARGET-OUTSIDE-NO-MUTATION",
|
|
22
|
+
"title": "the receiving entry stops checking the claimed target against the declared pair, so a declared remote can reach every deliverable citizen on this host",
|
|
23
|
+
"subject": "pi-extensions/lib/remote-pair-receive.ts",
|
|
24
|
+
"find": ["\tif (claim.target !== decl.localGardenId) {"],
|
|
25
|
+
"replace": ["\tif (false) {"],
|
|
26
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
27
|
+
"timeoutSeconds": 600,
|
|
28
|
+
"signature": "[QK:REMOTE-PAIR-TARGET-OUTSIDE-NO-MUTATION]",
|
|
29
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
30
|
+
"build": {
|
|
31
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
32
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"claim": "REMOTE-PAIR-IGNORES-AMBIENT-SENDER",
|
|
37
|
+
"title": "the receiving entry lets an ambient PI_SESSION_ID in the SSH environment stand in for the sender, so the header names whoever's carrier leaked instead of the claim",
|
|
38
|
+
"subject": "pi-extensions/lib/remote-pair-receive.ts",
|
|
39
|
+
"find": ["\t\tsessionId: claim.from,"],
|
|
40
|
+
"replace": ["\t\tsessionId: process.env.PI_SESSION_ID ?? claim.from,"],
|
|
41
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
42
|
+
"timeoutSeconds": 600,
|
|
43
|
+
"signature": "[QK:REMOTE-PAIR-IGNORES-AMBIENT-SENDER]",
|
|
44
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
45
|
+
"build": {
|
|
46
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
47
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
48
|
+
}
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"claim": "REMOTE-PAIR-MATCH-DISPATCHES-ONCE",
|
|
52
|
+
"title": "the receiving entry marks a remote sender replyable, so the body tells the receiver to reply via entwurf_v2 as if a live local reply route had been probed — none was",
|
|
53
|
+
"subject": "pi-extensions/lib/remote-pair-receive.ts",
|
|
54
|
+
"find": ["\t\treplyable: false,"],
|
|
55
|
+
"replace": ["\t\treplyable: true,"],
|
|
56
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
57
|
+
"timeoutSeconds": 600,
|
|
58
|
+
"signature": "[QK:REMOTE-PAIR-MATCH-DISPATCHES-ONCE]",
|
|
59
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
60
|
+
"build": {
|
|
61
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
62
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"claim": "REMOTE-PAIR-CLAIM-EXACT-SHAPE",
|
|
67
|
+
"title": "the claim parser accepts extra or missing fields, so a sender-side field the receiver never reads can ride in and a partial claim is dispatched",
|
|
68
|
+
"subject": "pi-extensions/lib/remote-pair-receive.ts",
|
|
69
|
+
"find": ["\tif (got.length !== want.length || got.some((k, i) => k !== want[i])) {"],
|
|
70
|
+
"replace": ["\tif (false) {"],
|
|
71
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
72
|
+
"timeoutSeconds": 600,
|
|
73
|
+
"signature": "[QK:REMOTE-PAIR-CLAIM-EXACT-SHAPE]",
|
|
74
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
75
|
+
"build": {
|
|
76
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
77
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"claim": "REMOTE-PAIR-ENTRY-REFUSES-OUTSIDE",
|
|
82
|
+
"title": "the entry reports a pair refusal as exit 0, so the sending host cannot tell a refused claim from a dispatched one without parsing prose",
|
|
83
|
+
"subject": "scripts/remote-pair-receive.ts",
|
|
84
|
+
"find": ["emit(receipt, receipt.kind === \"rejected\" ? 3 : receipt.isError ? 4 : 0);"],
|
|
85
|
+
"replace": ["emit(receipt, receipt.kind === \"rejected\" ? 0 : receipt.isError ? 4 : 0);"],
|
|
86
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
87
|
+
"timeoutSeconds": 600,
|
|
88
|
+
"signature": "[QK:REMOTE-PAIR-ENTRY-REFUSES-OUTSIDE]",
|
|
89
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
90
|
+
"build": {
|
|
91
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
92
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
"claim": "REMOTE-PAIR-ENTRY-USAGE",
|
|
97
|
+
"title": "the entry accepts any --pair it is given, so the sender picks which declaration scopes the claim on the receiving host",
|
|
98
|
+
"subject": "scripts/remote-pair-receive.ts",
|
|
99
|
+
"find": ["\tif (!path.isAbsolute(pairFile) || path.normalize(pairFile) !== own) {"],
|
|
100
|
+
"replace": ["\tif (false) {"],
|
|
101
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
102
|
+
"timeoutSeconds": 600,
|
|
103
|
+
"signature": "[QK:REMOTE-PAIR-ENTRY-USAGE]",
|
|
104
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
105
|
+
"build": {
|
|
106
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
107
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"claim": "REMOTE-PAIR-ENTRY-REPLY-ROUTE-DECLARED",
|
|
112
|
+
"title": "the entry reports no route back for a claim its own opt-in pairs with, so the receiver is told it cannot answer a sender it has declared",
|
|
113
|
+
"subject": "scripts/remote-pair-receive.ts",
|
|
114
|
+
"find": ["\treplyRoute: \"declared\","],
|
|
115
|
+
"replace": ["\treplyRoute: \"none\","],
|
|
116
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
117
|
+
"timeoutSeconds": 600,
|
|
118
|
+
"signature": "[QK:REMOTE-PAIR-ENTRY-REPLY-ROUTE-DECLARED]",
|
|
119
|
+
"signatureSource": "pi-extensions/lib/remote-pair-receive.test.ts",
|
|
120
|
+
"build": {
|
|
121
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
122
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
]
|
|
126
|
+
}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "remote-pair-roundtrip",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "REMOTE-ROUNDTRIP-A-TO-B",
|
|
7
|
+
"title": "the bridge never reads the opt-in, so a declared remote target falls through to the local decider as bad-target",
|
|
8
|
+
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
9
|
+
"find": ["\t\t\t\t\troute: readRemotePairOptIn(remotePairOptInPath()),"],
|
|
10
|
+
"replace": ["\t\t\t\t\troute: null,"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
12
|
+
"timeoutSeconds": 600,
|
|
13
|
+
"signature": "[QK:REMOTE-ROUNDTRIP-A-TO-B]",
|
|
14
|
+
"signatureSource": "pi-extensions/lib/remote-pair-roundtrip.test.ts",
|
|
15
|
+
"build": {
|
|
16
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
17
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
18
|
+
}
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"claim": "REMOTE-ROUNDTRIP-REVERSE-DISPATCH",
|
|
22
|
+
"title": "the bridge's transport never reaches the other host and always answers exit 1, so every declared remote send in either direction becomes indeterminate",
|
|
23
|
+
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
24
|
+
"find": ["\t\t\t\t\ttransport: processTransport,"],
|
|
25
|
+
"replace": [
|
|
26
|
+
"\t\t\t\t\ttransport: { run: async () => ({ exitCode: 1, signal: null, timedOut: false, stdout: \"\", stderr: \"\" }) },"
|
|
27
|
+
],
|
|
28
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
29
|
+
"timeoutSeconds": 600,
|
|
30
|
+
"signature": "[QK:REMOTE-ROUNDTRIP-REVERSE-DISPATCH]",
|
|
31
|
+
"signatureSource": "pi-extensions/lib/remote-pair-roundtrip.test.ts",
|
|
32
|
+
"build": {
|
|
33
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
34
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
"claim": "REMOTE-ROUNDTRIP-OPT-IN-ABSENT-OFF",
|
|
39
|
+
"title": "the bridge replaces the local surface on the remote path's behalf, so a host with no opt-in stops running the existing local decider",
|
|
40
|
+
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
41
|
+
"find": ["\t\t\t\t\trunLocal: (params, opts) => runAndRenderEntwurfV2FromSurface(params, opts),"],
|
|
42
|
+
"replace": ["\t\t\t\t\trunLocal: async () => ({ isError: false, text: \"local skipped\" }),"],
|
|
43
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
44
|
+
"timeoutSeconds": 600,
|
|
45
|
+
"signature": "[QK:REMOTE-ROUNDTRIP-OPT-IN-ABSENT-OFF]",
|
|
46
|
+
"signatureSource": "pi-extensions/lib/remote-pair-roundtrip.test.ts",
|
|
47
|
+
"build": {
|
|
48
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
49
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"claim": "REMOTE-ROUNDTRIP-OTHER-HOST-REFUSES",
|
|
54
|
+
"title": "the sender renders the other host's pair refusal without naming it, so A cannot tell B refused the pair from any other failure",
|
|
55
|
+
"subject": "pi-extensions/lib/remote-pair-send.ts",
|
|
56
|
+
"find": ["refused by the other host's pair: ${o.reason} (${o.detail})"],
|
|
57
|
+
"replace": ["failed"],
|
|
58
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
59
|
+
"timeoutSeconds": 600,
|
|
60
|
+
"signature": "[QK:REMOTE-ROUNDTRIP-OTHER-HOST-REFUSES]",
|
|
61
|
+
"signatureSource": "pi-extensions/lib/remote-pair-roundtrip.test.ts",
|
|
62
|
+
"build": {
|
|
63
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
64
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
65
|
+
}
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"claim": "REMOTE-ROUNDTRIP-LOCAL-TRACE-BOTH-SOCKET-DIRS",
|
|
69
|
+
"title": "the bridge checks only its own ENTWURF_DIR, so a live local socket in the decider's canonical dir is bypassed and the gid is sent away",
|
|
70
|
+
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
71
|
+
"find": ["\t\t\t\t\t\tcontrolSocketDirs: [CONTROL_SOCKET_DIR, ENTWURF_DIR],"],
|
|
72
|
+
"replace": ["\t\t\t\t\t\tcontrolSocketDirs: [ENTWURF_DIR],"],
|
|
73
|
+
"gate": ["bash", "run.sh", "check-tests-beside-behavior"],
|
|
74
|
+
"timeoutSeconds": 600,
|
|
75
|
+
"signature": "[QK:REMOTE-ROUNDTRIP-LOCAL-TRACE-BOTH-SOCKET-DIRS]",
|
|
76
|
+
"signatureSource": "pi-extensions/lib/remote-pair-roundtrip.test.ts",
|
|
77
|
+
"build": {
|
|
78
|
+
"argv": ["bash", "scripts/build-bridge.sh"],
|
|
79
|
+
"output": "mcp/entwurf-bridge/dist"
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
]
|
|
83
|
+
}
|