@junghanacs/entwurf 0.15.1 → 0.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/CHANGELOG.md +354 -0
- package/DELIVERY.md +3 -2
- package/README.md +68 -88
- package/VERIFY.md +4 -1
- package/demo/README.md +1 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +147 -9
- package/docs/setup-clean-host.md +125 -6
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +65 -20
- package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +19 -10
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +17 -6
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +172 -5
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +152 -17
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/omp-fresh-preflight.js +271 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-omp.js +988 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-receive-omp.js +574 -0
- package/mcp/entwurf-bridge/dist/scripts/omp-receive-facts.js +84 -0
- package/mcp/entwurf-bridge/src/index.ts +65 -19
- package/mcp/entwurf-bridge/tsconfig.build.json +19 -3
- package/mcp/tsconfig.json +10 -0
- package/package.json +19 -9
- package/pi/entwurf-capabilities.json +1 -0
- package/pi/meta-bridge-omp/entwurf-meta-omp/package.json +7 -0
- package/pi/omp-receive/entwurf-receive-omp/package.json +7 -0
- package/pi-extensions/entwurf-control.ts +12 -9
- package/pi-extensions/lib/acp/backend-adapter.ts +19 -9
- package/pi-extensions/lib/acp/backend.ts +125 -7
- package/pi-extensions/lib/acp/claude-acp-launch.js +100 -0
- package/pi-extensions/lib/entwurf-self-address.ts +18 -7
- package/pi-extensions/lib/meta-sender-identity.ts +1 -1
- package/pi-extensions/lib/meta-session.ts +219 -5
- package/pi-extensions/lib/mux-fresh-call.ts +171 -17
- package/pi-extensions/lib/omp-fresh-preflight.ts +275 -0
- package/pi-extensions/meta-bridge-omp.ts +1244 -0
- package/pi-extensions/meta-bridge-receive-omp.ts +666 -0
- package/run.sh +399 -31
- package/scripts/check-acp-launch-namespace.ts +127 -0
- package/scripts/check-acp-prompt-lifecycle.ts +145 -2
- package/scripts/check-copilot-birth-hook.ts +28 -1
- package/scripts/check-entwurf-self-address.ts +31 -0
- package/scripts/check-gate-qualification.ts +7 -3
- package/scripts/check-harness-admission-parity.ts +143 -0
- package/scripts/check-meta-doctor-oracle.sh +20 -0
- package/scripts/check-omp-birth-hook.ts +1049 -0
- package/scripts/check-omp-fresh-preflight.ts +208 -0
- package/scripts/check-omp-receive-arm.ts +516 -0
- package/scripts/check-setup-qualification.sh +40 -2
- package/scripts/copilot-bridge-oracle.sh +14 -6
- package/scripts/fake-copilot-vendor.sh +4 -2
- package/scripts/inventory-verification-surface.ts +1 -1
- package/scripts/meta-bridge-hook-log.sh +9 -1
- package/scripts/mutants/acp-launch-namespace.json +34 -0
- package/scripts/mutants/acp-prompt-lifecycle.json +67 -2
- package/scripts/mutants/copilot-birth.json +10 -10
- package/scripts/mutants/mux-fresh-call.json +22 -22
- package/scripts/mutants/omp-birth.json +173 -0
- package/scripts/mutants/omp-fresh.json +300 -0
- package/scripts/mutants/omp-receive.json +135 -0
- package/scripts/mutants/pack-install.json +2 -2
- package/scripts/mutants/self-address.json +34 -0
- package/scripts/mutants/setup-verdict.json +35 -0
- package/scripts/omp-bridge-doctor.sh +315 -0
- package/scripts/omp-bridge-install.sh +221 -0
- package/scripts/omp-bridge-oracle.sh +154 -0
- package/scripts/omp-bridge-uninstall.sh +57 -0
- package/scripts/omp-config-xdev.py +310 -0
- package/scripts/omp-config-xdev.sh +76 -0
- package/scripts/omp-mcp-bridge.sh +320 -0
- package/scripts/omp-mcp-config.py +392 -0
- package/scripts/omp-receive-doctor.sh +246 -0
- package/scripts/omp-receive-facts.ts +106 -0
- package/scripts/omp-receive-install.sh +228 -0
- package/scripts/omp-receive-uninstall.sh +60 -0
- package/scripts/omp-tool-surface.py +400 -0
- package/scripts/raw-acp-child-exit-measure/README.md +285 -0
- package/scripts/raw-acp-child-exit-measure/acp-turn-population.py +89 -0
- package/scripts/raw-acp-child-exit-measure/reaper-correlation.py +47 -0
- package/scripts/raw-omp-measure/README.md +420 -0
- package/scripts/raw-omp-measure/probe-extension.ts +76 -0
- package/scripts/raw-omp-measure/probe-receive-surface.ts +250 -0
- package/scripts/raw-omp-measure/source-audit.md +414 -0
- package/scripts/smoke-omp-bridge-state.sh +221 -0
- package/scripts/smoke-omp-fresh-live.ts +497 -0
- package/scripts/smoke-omp-mcp-state.sh +327 -0
- package/scripts/smoke-omp-receive-live.ts +340 -0
- package/scripts/smoke-omp-receive-state.sh +196 -0
- package/scripts/smoke-setup-verdict.sh +48 -3
- package/scripts/tsconfig.json +2 -0
|
@@ -90,7 +90,7 @@ const H_FS = /from\s+["']node:fs["']|require\(["']node:fs["']\)/;
|
|
|
90
90
|
// "process.env.LIVE"; it spawns no live turn of its own. So the predicate runs on the
|
|
91
91
|
// CODE-ONLY projection (comments and inert literals blanked, shell expansions kept)
|
|
92
92
|
// and matches a variable READ or an assignment, never prose.
|
|
93
|
-
const H_LIVE = /process\.env\.LIVE\b|\$\{LIVE[:}
|
|
93
|
+
const H_LIVE = /process\.env\.LIVE\b|\$\{LIVE[:}-]|\$LIVE\b|(?:^|\n)\s*(?:export\s+)?LIVE=1\b/;
|
|
94
94
|
|
|
95
95
|
/**
|
|
96
96
|
* Blank what cannot gate execution, so H_LIVE reads code and not prose.
|
|
@@ -15,10 +15,18 @@
|
|
|
15
15
|
# would make the CLAUDE doctor permanently red for a refusal on a different rail, with
|
|
16
16
|
# a prescription pointing at a Claude wake failure that never happened (cross-review,
|
|
17
17
|
# glm, 2026-08-21). Copilot's own recovery rule lives in copilot-bridge-doctor.sh.
|
|
18
|
+
#
|
|
19
|
+
# The OMP birth unit (#87) joins the same file tagged `LEVEL [omp]`, and the rule extends
|
|
20
|
+
# for the same reason plus a sharper one: omp's own scope fence writes a line for EVERY
|
|
21
|
+
# task subagent it refuses (`INFO [omp] scope-refused`), which is the designed answer, and
|
|
22
|
+
# its failures are mint/marker faults on a rail whose recovery token — `create`/`attach` —
|
|
23
|
+
# is not `armed watch` either. omp's recovery rule lives in omp-bridge-doctor.sh. Excluding
|
|
24
|
+
# a backend here is never a way to quiet a red: it is how each doctor keeps judging only
|
|
25
|
+
# the evidence it owns.
|
|
18
26
|
meta_bridge_hook_log_status() {
|
|
19
27
|
local log="$1"
|
|
20
28
|
local own
|
|
21
|
-
own="$(grep -v ' \[copilot\] ' "$log" 2>/dev/null || true)"
|
|
29
|
+
own="$(grep -v -e ' \[copilot\] ' -e ' \[omp\] ' "$log" 2>/dev/null || true)"
|
|
22
30
|
if ! printf '%s\n' "$own" | grep -q ' ERROR '; then
|
|
23
31
|
echo "no-error"
|
|
24
32
|
return 0
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "acp-launch-namespace",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "CLAUDE-LAUNCH-IS-NAMESPACED",
|
|
7
|
+
"title": "the default launch names the vendor bin directly again — the child re-enters the process-name space a janitor for another harness scans by substring, which is the whole of #72",
|
|
8
|
+
"subject": "pi-extensions/lib/acp/backend-adapter.ts",
|
|
9
|
+
"find": ["\tconst launcher = fileURLToPath(new URL(\"./claude-acp-launch.js\", import.meta.url));"],
|
|
10
|
+
"replace": ["\tconst launcher = require.resolve(\"@agentclientprotocol/claude-agent-acp/dist/index.js\");"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-acp-launch-namespace"],
|
|
12
|
+
"timeoutSeconds": 240,
|
|
13
|
+
"signature": "[QK:CLAUDE-LAUNCH-IS-NAMESPACED]",
|
|
14
|
+
"signatureSource": "scripts/check-acp-launch-namespace.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "CLAUDE-LAUNCH-IS-TRANSPARENT",
|
|
18
|
+
"title": "the launcher consumes an argv slot of its own — the vendor's argv.slice(1) self-reinvocation and its own flags stop working behind a name split that still looks correct",
|
|
19
|
+
"subject": "pi-extensions/lib/acp/claude-acp-launch.js",
|
|
20
|
+
"find": ["\tawait import(pathToFileURL(join(dirname(pkgJsonPath), binPath)).href);"],
|
|
21
|
+
"replace": [
|
|
22
|
+
"\tif (process.argv.includes(\"--version\")) {",
|
|
23
|
+
"\t\tconsole.log(\"entwurf launcher\");",
|
|
24
|
+
"\t\tprocess.exit(0);",
|
|
25
|
+
"\t}",
|
|
26
|
+
"\tawait import(pathToFileURL(join(dirname(pkgJsonPath), binPath)).href);"
|
|
27
|
+
],
|
|
28
|
+
"gate": ["bash", "run.sh", "check-acp-launch-namespace"],
|
|
29
|
+
"timeoutSeconds": 240,
|
|
30
|
+
"signature": "[QK:CLAUDE-LAUNCH-IS-TRANSPARENT]",
|
|
31
|
+
"signatureSource": "scripts/check-acp-launch-namespace.ts"
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
@@ -54,8 +54,8 @@
|
|
|
54
54
|
"claim": "REUSE-CARRIES-CHILD-DIAGNOSTICS",
|
|
55
55
|
"title": "the reuse path drops the child's stderr tail again — exactly the live sonnet failure that showed only \"ACP connection closed\"",
|
|
56
56
|
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
57
|
-
"find": ["\t\t\tfinishError(err, aborted, session.stderrTail, lifecycle);"],
|
|
58
|
-
"replace": ["\t\t\tfinishError(err, aborted, undefined, lifecycle);"],
|
|
57
|
+
"find": ["\t\t\tfinishError(err, aborted, session.stderrTail, lifecycle, session.launchObservation);"],
|
|
58
|
+
"replace": ["\t\t\tfinishError(err, aborted, undefined, lifecycle, session.launchObservation);"],
|
|
59
59
|
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
60
60
|
"timeoutSeconds": 180,
|
|
61
61
|
"signature": "[QK:REUSE-CARRIES-CHILD-DIAGNOSTICS]",
|
|
@@ -117,6 +117,71 @@
|
|
|
117
117
|
"timeoutSeconds": 180,
|
|
118
118
|
"signature": "[QK:CHILD-END-SILENCE-BOUNDED]",
|
|
119
119
|
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
"claim": "LAUNCH-SIGNAL-EVIDENCE-STRUCTURED",
|
|
123
|
+
"title": "the caught-signal observation is dropped from the report — an externally killed child again reads as a clean vendor exit, the exact ambiguity #72 cost three diagnosis passes",
|
|
124
|
+
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
125
|
+
"find": ["\t\tconst diagnosed = observed ? `${withLifecycle}\\n${observed}` : withLifecycle;"],
|
|
126
|
+
"replace": ["\t\tconst diagnosed = withLifecycle;"],
|
|
127
|
+
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
128
|
+
"timeoutSeconds": 180,
|
|
129
|
+
"signature": "[QK:LAUNCH-SIGNAL-EVIDENCE-STRUCTURED]",
|
|
130
|
+
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
"claim": "LAUNCH-FRAME-NOT-IN-TAIL",
|
|
134
|
+
"title": "the launcher's control frame is echoed into the vendor stderr tail — entwurf's own fact is laundered back into vendor evidence",
|
|
135
|
+
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
136
|
+
"find": ["\t\t\tspawned.stderr.on(\"data\", (c: Buffer) => consumeStderr.write(c.toString()));"],
|
|
137
|
+
"replace": [
|
|
138
|
+
"\t\t\tspawned.stderr.on(\"data\", (c: Buffer) => {",
|
|
139
|
+
"\t\t\t\tconsumeStderr.write(c.toString());",
|
|
140
|
+
"\t\t\t\tstderrTail.push(c.toString());",
|
|
141
|
+
"\t\t\t});"
|
|
142
|
+
],
|
|
143
|
+
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
144
|
+
"timeoutSeconds": 180,
|
|
145
|
+
"signature": "[QK:LAUNCH-FRAME-NOT-IN-TAIL]",
|
|
146
|
+
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
"claim": "LAUNCH-SIGNAL-EXACT-FRAME-ONLY",
|
|
150
|
+
"title": "the frame is matched by prefix without its fixed enum — vendor prose can forge an entwurf-owned observation",
|
|
151
|
+
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
152
|
+
"find": [
|
|
153
|
+
"\t\t\t\tif (",
|
|
154
|
+
"\t\t\t\t\tline.startsWith(LAUNCH_SIGNAL_FRAME_PREFIX) &&",
|
|
155
|
+
"\t\t\t\t\tLAUNCH_SIGNAL_FRAME_VALUES.has(line.slice(LAUNCH_SIGNAL_FRAME_PREFIX.length))",
|
|
156
|
+
"\t\t\t\t) {"
|
|
157
|
+
],
|
|
158
|
+
"replace": ["\t\t\t\tif (line.includes(LAUNCH_SIGNAL_FRAME_PREFIX)) {"],
|
|
159
|
+
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
160
|
+
"timeoutSeconds": 180,
|
|
161
|
+
"signature": "[QK:LAUNCH-SIGNAL-EXACT-FRAME-ONLY]",
|
|
162
|
+
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"claim": "STDERR-TAIL-FLUSHES-PARTIAL-LINE",
|
|
166
|
+
"title": "the line buffer never flushes its unterminated remainder — a child that dies mid-write loses the dying words the stderr tail exists to carry",
|
|
167
|
+
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
168
|
+
"find": ["\t\t\tspawned.stderr.once?.(\"close\", () => consumeStderr.flush());"],
|
|
169
|
+
"replace": ["\t\t\tvoid consumeStderr;"],
|
|
170
|
+
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
171
|
+
"timeoutSeconds": 180,
|
|
172
|
+
"signature": "[QK:STDERR-TAIL-FLUSHES-PARTIAL-LINE]",
|
|
173
|
+
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
"claim": "LAUNCH-FRAME-SPANS-CHUNKS",
|
|
177
|
+
"title": "the frame is matched per read instead of per line — a frame split across a chunk boundary is missed, and the external kill goes unreported exactly as it did in the field",
|
|
178
|
+
"subject": "pi-extensions/lib/acp/backend.ts",
|
|
179
|
+
"find": ["\t\t\theld += chunk;"],
|
|
180
|
+
"replace": ["\t\t\theld = chunk;"],
|
|
181
|
+
"gate": ["bash", "run.sh", "check-acp-prompt-lifecycle"],
|
|
182
|
+
"timeoutSeconds": 180,
|
|
183
|
+
"signature": "[QK:LAUNCH-FRAME-SPANS-CHUNKS]",
|
|
184
|
+
"signatureSource": "scripts/check-acp-prompt-lifecycle.ts"
|
|
120
185
|
}
|
|
121
186
|
]
|
|
122
187
|
}
|
|
@@ -94,10 +94,10 @@
|
|
|
94
94
|
},
|
|
95
95
|
{
|
|
96
96
|
"claim": "HOOK-LOG-RAIL-SCOPED",
|
|
97
|
-
"title": "
|
|
97
|
+
"title": "dropping the copilot tag from the shared-hook-log filter lets a Copilot fail-closed refusal redden the CLAUDE doctor forever \u2014 copilot's recovery token cannot exist on that rail",
|
|
98
98
|
"subject": "scripts/meta-bridge-hook-log.sh",
|
|
99
|
-
"find": [" own=\"$(grep -v ' \\[copilot\\] ' \"$log\" 2>/dev/null || true)\""],
|
|
100
|
-
"replace": [" own=\"$(
|
|
99
|
+
"find": [" own=\"$(grep -v -e ' \\[copilot\\] ' -e ' \\[omp\\] ' \"$log\" 2>/dev/null || true)\""],
|
|
100
|
+
"replace": [" own=\"$(grep -v ' \\[omp\\] ' \"$log\" 2>/dev/null || true)\""],
|
|
101
101
|
"gate": ["bash", "run.sh", "check-meta-doctor-oracle"],
|
|
102
102
|
"timeoutSeconds": 600,
|
|
103
103
|
"signature": "[QK:HOOK-LOG-RAIL-SCOPED]",
|
|
@@ -132,9 +132,11 @@
|
|
|
132
132
|
"title": "closing the reader half leaves the writer talking to nobody — the hook writes a copilot marker, the bridge never looks in that directory, and the citizen's sends are refused as anonymous (the #46 shape, which is why writer and reader open in one change)",
|
|
133
133
|
"subject": "pi-extensions/lib/meta-sender-identity.ts",
|
|
134
134
|
"find": [
|
|
135
|
-
"export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\"];"
|
|
135
|
+
"export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\", \"omp\"];"
|
|
136
|
+
],
|
|
137
|
+
"replace": [
|
|
138
|
+
"export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"omp\"];"
|
|
136
139
|
],
|
|
137
|
-
"replace": ["export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\"];"],
|
|
138
140
|
"gate": ["bash", "run.sh", "check-copilot-birth-hook"],
|
|
139
141
|
"timeoutSeconds": 300,
|
|
140
142
|
"signature": "[QK:COPILOT-SENDER-READER-OPEN]",
|
|
@@ -194,12 +196,10 @@
|
|
|
194
196
|
},
|
|
195
197
|
{
|
|
196
198
|
"claim": "COPILOT-MALFORMED-ROW-NOT-ABSENT",
|
|
197
|
-
"title": "a truncated/garbled exact plugin row falls through the parser and rounds to ABSENT, which the inverse reads as retry-safe absence and continues past — the exact fall-through B reproduced (`(v0.1` with no closing paren) against 47a5ae3 (#86 C3a corrective amendment, B defect 3)",
|
|
199
|
+
"title": "a truncated/garbled exact plugin row falls through the parser and rounds to ABSENT, which the inverse reads as retry-safe absence and continues past — the exact fall-through B reproduced (`(v0.1` with no closing paren) against 47a5ae3 (#86 C3a corrective amendment, B defect 3). The parse became a regex when the 1.0.81 state token was admitted; the fall-through must stay closed on either spelling.",
|
|
198
200
|
"subject": "scripts/copilot-bridge-oracle.sh",
|
|
199
|
-
"find": [
|
|
200
|
-
|
|
201
|
-
],
|
|
202
|
-
"replace": [" if not (rest.startswith(\"(v\") and rest.endswith(\")\")):\n continue"],
|
|
201
|
+
"find": [" match = ROW_TAIL.fullmatch(rest)\n if match is None:"],
|
|
202
|
+
"replace": [" match = ROW_TAIL.fullmatch(rest)\n if match is None:\n continue\n if False:"],
|
|
203
203
|
"gate": ["bash", "run.sh", "check-copilot-birth-hook"],
|
|
204
204
|
"timeoutSeconds": 300,
|
|
205
205
|
"signature": "[QK:COPILOT-MALFORMED-ROW-NOT-ABSENT]",
|
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
"claim": "FRESHCALL-PI-ARGV-PROMPT-FIRST",
|
|
7
7
|
"title": "pi gets the flag before the prompt again — the measured shape that opens a window whose first turn never runs",
|
|
8
8
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
9
|
-
"find": ["\t\t\treturn [prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
10
|
-
"replace": ["\t\t\treturn [\"--entwurf-control\", prompt, \"--model\", model];"],
|
|
9
|
+
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
10
|
+
"replace": ["\t\t\treturn [\"--entwurf-control\", composition.prompt, \"--model\", model];"],
|
|
11
11
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
12
12
|
"timeoutSeconds": 120,
|
|
13
13
|
"signature": "[QK:FRESHCALL-PI-ARGV-PROMPT-FIRST]",
|
|
@@ -18,10 +18,10 @@
|
|
|
18
18
|
"title": "claude-code goes back to the variadic space form, which swallows the prompt as an option value",
|
|
19
19
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
20
20
|
"find": [
|
|
21
|
-
"\t\t\treturn [prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
21
|
+
"\t\t\treturn [composition.prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
22
22
|
],
|
|
23
23
|
"replace": [
|
|
24
|
-
"\t\t\treturn [prompt, \"--allowedTools\", FRESH_CALL_CALLBACK_TOOL[\"claude-code\"], `--model=${model}`];"
|
|
24
|
+
"\t\t\treturn [composition.prompt, \"--allowedTools\", FRESH_CALL_CALLBACK_TOOL[\"claude-code\"], `--model=${model}`];"
|
|
25
25
|
],
|
|
26
26
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
27
27
|
"timeoutSeconds": 120,
|
|
@@ -32,8 +32,8 @@
|
|
|
32
32
|
"claim": "FRESHCALL-PI-MODEL-ARGV",
|
|
33
33
|
"title": "pi drops its measured two-token model option and silently resolves its ambient default again",
|
|
34
34
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
35
|
-
"find": ["\t\t\treturn [prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
36
|
-
"replace": ["\t\t\treturn [prompt, \"--entwurf-control\"];"],
|
|
35
|
+
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
36
|
+
"replace": ["\t\t\treturn [composition.prompt, \"--entwurf-control\"];"],
|
|
37
37
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
38
38
|
"timeoutSeconds": 120,
|
|
39
39
|
"signature": "[QK:FRESHCALL-PI-MODEL-ARGV]",
|
|
@@ -43,8 +43,8 @@
|
|
|
43
43
|
"claim": "FRESHCALL-PI-MODEL-DIALECT",
|
|
44
44
|
"title": "pi model argv is unified with Claude Code into the equals form that the real Pi parser rejects",
|
|
45
45
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
46
|
-
"find": ["\t\t\treturn [prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
47
|
-
"replace": ["\t\t\treturn [prompt, \"--entwurf-control\", `--model=${model}`];"],
|
|
46
|
+
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
47
|
+
"replace": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", `--model=${model}`];"],
|
|
48
48
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
49
49
|
"timeoutSeconds": 120,
|
|
50
50
|
"signature": "[QK:FRESHCALL-PI-MODEL-DIALECT]",
|
|
@@ -55,9 +55,9 @@
|
|
|
55
55
|
"title": "Claude Code drops the explicit model token and silently resolves its ambient Opus default again",
|
|
56
56
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
57
57
|
"find": [
|
|
58
|
-
"\t\t\treturn [prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
58
|
+
"\t\t\treturn [composition.prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
59
59
|
],
|
|
60
|
-
"replace": ["\t\t\treturn [prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`];"],
|
|
60
|
+
"replace": ["\t\t\treturn [composition.prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`];"],
|
|
61
61
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
62
62
|
"timeoutSeconds": 120,
|
|
63
63
|
"signature": "[QK:FRESHCALL-CLAUDE-MODEL-ARGV]",
|
|
@@ -240,8 +240,8 @@
|
|
|
240
240
|
"claim": "FRESHCALL-COPILOT-ARGV-INTERACTIVE",
|
|
241
241
|
"title": "the Copilot prompt rides -p instead of --interactive — the turn runs and the CLI EXITS, closing the window on a sibling that was supposed to stay open",
|
|
242
242
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
243
|
-
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model, \"--yolo\"];"],
|
|
244
|
-
"replace": ["\t\t\treturn [\"copilot\", \"-p\", prompt, \"--model\", model, \"--yolo\"];"],
|
|
243
|
+
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
244
|
+
"replace": ["\t\t\treturn [\"copilot\", \"-p\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
245
245
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
246
246
|
"timeoutSeconds": 180,
|
|
247
247
|
"signature": "[QK:FRESHCALL-COPILOT-ARGV-INTERACTIVE]",
|
|
@@ -251,8 +251,8 @@
|
|
|
251
251
|
"claim": "FRESHCALL-COPILOT-MODEL-ARGV",
|
|
252
252
|
"title": "the Copilot argv drops the explicit model — the managed launcher then injects `--model auto` and the caller's model choice is silently discarded",
|
|
253
253
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
254
|
-
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model, \"--yolo\"];"],
|
|
255
|
-
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--yolo\"];"],
|
|
254
|
+
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
255
|
+
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--yolo\"];"],
|
|
256
256
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
257
257
|
"timeoutSeconds": 180,
|
|
258
258
|
"signature": "[QK:FRESHCALL-COPILOT-MODEL-ARGV]",
|
|
@@ -262,9 +262,9 @@
|
|
|
262
262
|
"claim": "FRESHCALL-COPILOT-YOLO-POLICY",
|
|
263
263
|
"title": "the policy token narrows back to the callback-only --allow-tool grant — the exact regression GLG measured on 2026-08-25: no YOLO in the footer, a confirmation prompt at every task tool, an impractical sibling",
|
|
264
264
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
265
|
-
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model, \"--yolo\"];"],
|
|
265
|
+
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
266
266
|
"replace": [
|
|
267
|
-
"\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model, \"--allow-tool=entwurf-bridge(entwurf_v2)\"];"
|
|
267
|
+
"\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--allow-tool=entwurf-bridge(entwurf_v2)\"];"
|
|
268
268
|
],
|
|
269
269
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
270
270
|
"timeoutSeconds": 180,
|
|
@@ -312,8 +312,8 @@
|
|
|
312
312
|
"claim": "FRESHCALL-BACKEND-SET-SURFACE-PARITY",
|
|
313
313
|
"title": "a backend the composition can open is missing from the MCP surface enum — the capability exists and no external host can reach it",
|
|
314
314
|
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
315
|
-
"find": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\"])"],
|
|
316
|
-
"replace": ["\t\t\t.enum([\"pi\", \"claude-code\"])"],
|
|
315
|
+
"find": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\", \"omp\"])"],
|
|
316
|
+
"replace": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\"])"],
|
|
317
317
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
318
318
|
"timeoutSeconds": 180,
|
|
319
319
|
"signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY]",
|
|
@@ -421,8 +421,8 @@
|
|
|
421
421
|
"claim": "FRESHCALL-COPILOT-EXPLICIT-POLICY",
|
|
422
422
|
"title": "the composition stops stating its policy and silently leans on the launcher to inject --yolo — the effective profile survives but the fresh contract loses its explicit permission statement",
|
|
423
423
|
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
424
|
-
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model, \"--yolo\"];"],
|
|
425
|
-
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", prompt, \"--model\", model];"],
|
|
424
|
+
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
425
|
+
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model];"],
|
|
426
426
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
427
427
|
"timeoutSeconds": 180,
|
|
428
428
|
"signature": "[QK:FRESHCALL-COPILOT-EXPLICIT-POLICY]",
|
|
@@ -432,8 +432,8 @@
|
|
|
432
432
|
"claim": "FRESHCALL-BACKEND-SET-SURFACE-PARITY-PI",
|
|
433
433
|
"title": "a backend the composition can open is missing from the native pi surface enum — an in-process pi session cannot name a capability the module already opens",
|
|
434
434
|
"subject": "pi-extensions/entwurf-control.ts",
|
|
435
|
-
"find": ["\t\t\tbackend: StringEnum([\"pi\", \"claude-code\", \"copilot\"], {"],
|
|
436
|
-
"replace": ["\t\t\tbackend: StringEnum([\"pi\", \"claude-code\"], {"],
|
|
435
|
+
"find": ["\t\t\tbackend: StringEnum([\"pi\", \"claude-code\", \"copilot\", \"omp\"], {"],
|
|
436
|
+
"replace": ["\t\t\tbackend: StringEnum([\"pi\", \"claude-code\", \"copilot\"], {"],
|
|
437
437
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
438
438
|
"timeoutSeconds": 180,
|
|
439
439
|
"signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY-PI]",
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "omp-birth",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "OMP-BIRTH-TUI-MINTS",
|
|
7
|
+
"title": "a birth unit whose host predicate is not the vendor's tui mode mints nothing for the operator's own session — the visible sibling never becomes a citizen",
|
|
8
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
9
|
+
"find": ["const HOST_MODE = \"tui\";"],
|
|
10
|
+
"replace": ["const HOST_MODE = \"print\";"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
12
|
+
"timeoutSeconds": 300,
|
|
13
|
+
"signature": "[QK:OMP-BIRTH-TUI-MINTS]",
|
|
14
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "OMP-BIRTH-SCOPE-FENCE",
|
|
18
|
+
"title": "a fence that admits `print` gives every task subagent its own garden id — each visible omp session would mint a citizen per internal agent, which is the exact thing #87 exists to prevent",
|
|
19
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
20
|
+
"find": ["\tif (ctx.mode !== HOST_MODE) {"],
|
|
21
|
+
"replace": ["\tif (ctx.mode !== HOST_MODE && ctx.mode !== \"print\") {"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
23
|
+
"timeoutSeconds": 300,
|
|
24
|
+
"signature": "[QK:OMP-BIRTH-SCOPE-FENCE]",
|
|
25
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"claim": "OMP-BIRTH-BINDS-BOTH-EDGES",
|
|
29
|
+
"title": "binding only session_start leaves every post-/new, forked and in-TUI-resumed session unminted while its status line still shows the previous citizen's id (the switch edge is where those re-fire, audit C2)",
|
|
30
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
31
|
+
"find": [
|
|
32
|
+
"\tpi.on(\"session_switch\", (event, ctx) =>",
|
|
33
|
+
"\t\tonBirthEdge(`session_switch(${asNonEmptyString(event?.reason) || \"unlabeled\"})`, ctx, pi),",
|
|
34
|
+
"\t);"
|
|
35
|
+
],
|
|
36
|
+
"replace": ["\t// session_switch left unbound"],
|
|
37
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
38
|
+
"timeoutSeconds": 300,
|
|
39
|
+
"signature": "[QK:OMP-BIRTH-BINDS-BOTH-EDGES]",
|
|
40
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"claim": "OMP-BIRTH-SHOWS-GARDEN-ID",
|
|
44
|
+
"title": "a citizen whose garden id never reaches the vendor's own status surface has an address visible only by scraping records — not lifecycle parity (adding-a-harness.md step 4)",
|
|
45
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
46
|
+
"find": ["\t\tshowGardenId(ctx, result.record.gardenId);"],
|
|
47
|
+
"replace": ["\t\t// visible identity dropped"],
|
|
48
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
49
|
+
"timeoutSeconds": 300,
|
|
50
|
+
"signature": "[QK:OMP-BIRTH-SHOWS-GARDEN-ID]",
|
|
51
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"claim": "OMP-SENDER-MARKER-OWN-PID",
|
|
55
|
+
"title": "keying the marker to process.ppid copies the exec'd backends' parent join into a runtime that has no launcher — the marker names the shell that started omp, and no bridge child ever looks there",
|
|
56
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
57
|
+
"find": ["\tconst ownerPid = process.pid;"],
|
|
58
|
+
"replace": ["\tconst ownerPid = process.ppid;"],
|
|
59
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
60
|
+
"timeoutSeconds": 300,
|
|
61
|
+
"signature": "[QK:OMP-SENDER-MARKER-OWN-PID]",
|
|
62
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"claim": "OMP-SENDER-READER-OPEN",
|
|
66
|
+
"title": "a backend whose hook writes a marker but is absent from the reader list is INVISIBLE — the bridge holds the owner pid, never looks in that directory, and every send is refused as anonymous for a reason nothing logs (the #46 defect)",
|
|
67
|
+
"subject": "pi-extensions/lib/meta-sender-identity.ts",
|
|
68
|
+
"find": [
|
|
69
|
+
"export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\", \"omp\"];"
|
|
70
|
+
],
|
|
71
|
+
"replace": [
|
|
72
|
+
"export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\"];"
|
|
73
|
+
],
|
|
74
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
75
|
+
"timeoutSeconds": 300,
|
|
76
|
+
"signature": "[QK:OMP-SENDER-READER-OPEN]",
|
|
77
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"claim": "OMP-BIRTH-DOES-NOT-ARM-RECEIVER",
|
|
81
|
+
"title": "birth arming a receiver claims a live process holds a watch that nothing holds — the citizen reads DELIVERABLE, wired to nothing, for as long as the TUI stays open. This plants a REAL record-bound marker the certified reader accepts (an empty meta-receivers/ directory arms nothing and would be killed for the wrong reason)",
|
|
82
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
83
|
+
"find": ["\t\twriteOmpSenderMarker(result.record.gardenId, envelope);"],
|
|
84
|
+
"replace": [
|
|
85
|
+
"\t\twriteOmpSenderMarker(result.record.gardenId, envelope);",
|
|
86
|
+
"\t\tconst receiversDir = roots().receiversDir;",
|
|
87
|
+
"\t\tfs.mkdirSync(receiversDir, { recursive: true });",
|
|
88
|
+
"\t\tfs.writeFileSync(",
|
|
89
|
+
"\t\t\tpath.join(receiversDir, `${result.record.gardenId}.json`),",
|
|
90
|
+
"\t\t\t`${JSON.stringify({",
|
|
91
|
+
"\t\t\t\tgardenId: result.record.gardenId,",
|
|
92
|
+
"\t\t\t\tbackend: BACKEND,",
|
|
93
|
+
"\t\t\t\tnativeSessionId: envelope.nativeSessionId,",
|
|
94
|
+
"\t\t\t\townerPid: process.pid,",
|
|
95
|
+
"\t\t\t\townerStartKey: \"planted-by-mutant\",",
|
|
96
|
+
"\t\t\t\townerKind: \"omp-tui\",",
|
|
97
|
+
"\t\t\t\tarmProvenance: \"session-start\",",
|
|
98
|
+
"\t\t\t\tupdatedAt: new Date().toISOString(),",
|
|
99
|
+
"\t\t\t})}\\n`,",
|
|
100
|
+
"\t\t);"
|
|
101
|
+
],
|
|
102
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
103
|
+
"timeoutSeconds": 300,
|
|
104
|
+
"signature": "[QK:OMP-BIRTH-DOES-NOT-ARM-RECEIVER]",
|
|
105
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"claim": "OMP-BIRTH-CWD-DISAGREEMENT",
|
|
109
|
+
"title": "preferring one cwd when the two vendor-authoritative sources disagree mints a record keyed to a directory the session is not in — a guess exactly where the disagreement was the interesting fact",
|
|
110
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
111
|
+
"find": [
|
|
112
|
+
"\tif (ctxCwd && managerCwd && ctxCwd !== managerCwd) {",
|
|
113
|
+
"\t\treturn { refusal: `ctx.cwd and sessionManager.getCwd() disagree (${ctxCwd} vs ${managerCwd})` };",
|
|
114
|
+
"\t}"
|
|
115
|
+
],
|
|
116
|
+
"replace": ["\t// disagreement tolerated: ctx.cwd simply wins"],
|
|
117
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
118
|
+
"timeoutSeconds": 300,
|
|
119
|
+
"signature": "[QK:OMP-BIRTH-CWD-DISAGREEMENT]",
|
|
120
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"claim": "OMP-META-ROOT-JOINT-BINDING",
|
|
124
|
+
"title": "restoring the legacy PI_CODING_AGENT_DIR fallback inside the SHARED omp root base splits the garden store on an ordinary `omp --profile work`: the birth extension mints its record and sender marker under the vendor's profile agent dir — a pi sandbox, if that is where the value came from — and the omp-labeled bridge child pins its four roots to the same wrong bundle. Mutating the shared base replants the defect in BOTH consumers at once, which is why the subject is the common policy rather than either call site",
|
|
125
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
126
|
+
"find": [
|
|
127
|
+
"\t// NEVER `piAgentDir()` here: for backend omp that variable is the VENDOR's agent dir.",
|
|
128
|
+
"\treturn path.join(home, \".pi\", \"agent\");"
|
|
129
|
+
],
|
|
130
|
+
"replace": [
|
|
131
|
+
"\treturn env.PI_CODING_AGENT_DIR",
|
|
132
|
+
"\t\t? path.resolve(expandTildeIn(env.PI_CODING_AGENT_DIR, home))",
|
|
133
|
+
"\t\t: path.join(home, \".pi\", \"agent\");"
|
|
134
|
+
],
|
|
135
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
136
|
+
"timeoutSeconds": 300,
|
|
137
|
+
"signature": "[QK:OMP-META-ROOT-JOINT-BINDING]",
|
|
138
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
"claim": "OMP-META-ROOT-ABSOLUTE-ONLY",
|
|
142
|
+
"title": "resolving a relative ENTWURF_META_* override instead of refusing it makes each process's working directory a garden-root authority: the omp extension resolves it against wherever the operator launched omp while the doctor resolves it against the repository (run_ts cd's there), so the doctor reports NOT-YET off an empty directory while the extension's real store holds records. Both halves read this one leaf, so removing the fail-closed branch splits them at the same instant",
|
|
143
|
+
"subject": "pi-extensions/lib/meta-session.ts",
|
|
144
|
+
"find": [
|
|
145
|
+
"\t\tif (override === \"~\" || override.startsWith(\"~/\")) return path.resolve(expandTildeIn(override, home));",
|
|
146
|
+
"\t\tif (path.isAbsolute(override)) return path.resolve(override);",
|
|
147
|
+
"\t\tthrow new MetaRootPolicyError(",
|
|
148
|
+
"\t\t\t`omp meta-root policy refuses ${key}=${JSON.stringify(override)}: a garden root must be absolute or ~-rooted ` +",
|
|
149
|
+
"\t\t\t\t\"(`~` or `~/…`). A relative value would resolve against each process's own working directory, and the omp \" +",
|
|
150
|
+
"\t\t\t\t\"extension and its doctor do not share one — set an absolute path, or unset it to use the default under HOME.\",",
|
|
151
|
+
"\t\t);"
|
|
152
|
+
],
|
|
153
|
+
"replace": ["\t\treturn path.resolve(expandTildeIn(override, home));"],
|
|
154
|
+
"gate": ["bash", "run.sh", "check-omp-birth-hook"],
|
|
155
|
+
"timeoutSeconds": 300,
|
|
156
|
+
"signature": "[QK:OMP-META-ROOT-ABSOLUTE-ONLY]",
|
|
157
|
+
"signatureSource": "scripts/check-omp-birth-hook.ts"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"claim": "OMP-DOCTOR-CARRIER-TRIMS",
|
|
161
|
+
"title": "treating an empty or whitespace-only PI carrier as an inherited identity makes Bundle C's deliberate tmux `-e NAME=` scrub fail the deterministic floor whenever a visible fresh omp citizen is alive",
|
|
162
|
+
"subject": "scripts/omp-bridge-doctor.sh",
|
|
163
|
+
"find": [
|
|
164
|
+
" if tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -qE '^(PI_SESSION_ID|PI_AGENT_ID)=.*[^[:space:]]'; then"
|
|
165
|
+
],
|
|
166
|
+
"replace": [" if tr '\\0' '\\n' < \"$ENVIRON\" 2>/dev/null | grep -qE '^(PI_SESSION_ID|PI_AGENT_ID)='; then"],
|
|
167
|
+
"gate": ["bash", "run.sh", "smoke-omp-bridge-state"],
|
|
168
|
+
"timeoutSeconds": 300,
|
|
169
|
+
"signature": "[QK:OMP-DOCTOR-CARRIER-TRIMS]",
|
|
170
|
+
"signatureSource": "scripts/smoke-omp-bridge-state.sh"
|
|
171
|
+
}
|
|
172
|
+
]
|
|
173
|
+
}
|