@junghanacs/entwurf 0.15.1 → 0.16.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/CHANGELOG.md +229 -0
- package/DELIVERY.md +3 -2
- package/README.md +70 -87
- package/VERIFY.md +4 -1
- package/docs/acp-backend-rail.md +1 -1
- package/docs/external-mcp-host.md +147 -9
- package/docs/setup-clean-host.md +105 -0
- 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/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 +13 -3
- 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/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 +296 -4
- package/scripts/check-entwurf-self-address.ts +31 -0
- package/scripts/check-gate-qualification.ts +4 -1
- 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 +181 -0
- package/scripts/check-omp-receive-arm.ts +516 -0
- package/scripts/inventory-verification-surface.ts +1 -1
- package/scripts/meta-bridge-hook-log.sh +9 -1
- package/scripts/mutants/copilot-birth.json +7 -5
- 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/self-address.json +34 -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-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 +349 -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/tsconfig.json +2 -0
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "omp-fresh",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "ADMISSION-FRESH-PARITY",
|
|
7
|
+
"title": "a post-#82 harness admitted as a full D6 citizen while entwurf_fresh_call cannot open it — the exact state the Bundle A+B candidate shipped in, where every gate was green and only prose said the backend was unsupported. This is the defect the whole gate exists for: without it, an `unsupported` note reads as a partial-release permit",
|
|
8
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
9
|
+
"find": ["export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"omp\"] as const;"],
|
|
10
|
+
"replace": ["export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\"] as const;"],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-harness-admission-parity"],
|
|
12
|
+
"timeoutSeconds": 300,
|
|
13
|
+
"signature": "[QK:ADMISSION-FRESH-PARITY]",
|
|
14
|
+
"signatureSource": "scripts/check-harness-admission-parity.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "ADMISSION-LEGACY-DOCUMENTED",
|
|
18
|
+
"title": "a pre-#82 exception that only the gate believes in — the matrix sentence removed while the gate literal stays, so an operator reading DELIVERY.md finds a shipped citizen with no statement that it was never evaluated under step 9. The exclusion half of check-release-gate-outcomes cell 7, replanted on the admission axis",
|
|
19
|
+
"subject": "DELIVERY.md",
|
|
20
|
+
"find": [
|
|
21
|
+
" Admitted before the #82 step 9 contract and not re-evaluated under it, so it is legacy citizen evidence, not a step-9 supported harness: `entwurf_fresh_call` cannot open an agy sibling, and nothing here should be read as claiming visible lifecycle parity."
|
|
22
|
+
],
|
|
23
|
+
"replace": [""],
|
|
24
|
+
"gate": ["bash", "run.sh", "check-harness-admission-parity"],
|
|
25
|
+
"timeoutSeconds": 300,
|
|
26
|
+
"signature": "[QK:ADMISSION-LEGACY-DOCUMENTED]",
|
|
27
|
+
"signatureSource": "scripts/check-harness-admission-parity.ts"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"claim": "FRESHCALL-OMP-EXPLICIT-POLICY",
|
|
31
|
+
"title": "the permission width dropped from the omp argv. NOTHING OBSERVABLE FAILS: omp 18.0.0's schema default for tools.approvalMode is ALREADY yolo, so the sibling still boots and a LIVE acceptance still passes — the argv has simply started depending on a vendor default and on whatever the operator's config happens to say. This is the drift step 9 clause 2 forbids, and it is invisible to every test that only watches behaviour",
|
|
32
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
33
|
+
"find": [
|
|
34
|
+
"\t\t\treturn [`--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model, \"--approval-mode\", \"yolo\"];"
|
|
35
|
+
],
|
|
36
|
+
"replace": ["\t\t\treturn [`--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model];"],
|
|
37
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
38
|
+
"timeoutSeconds": 300,
|
|
39
|
+
"signature": "[QK:FRESHCALL-OMP-EXPLICIT-POLICY]",
|
|
40
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"claim": "FRESHCALL-OMP-CALLBACK-TOOL-DIALECT",
|
|
44
|
+
"title": "the callback tool name spelled the way a reader expects instead of the way omp mints it — `entwurf_v2` keeps its digit, which omp's sanitizer charset [a-z_] eats. The sibling is told to call a tool that does not exist in its session, so the whole first turn is spent and no address ever comes back. A launch receipt still prints",
|
|
45
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
46
|
+
"find": ["\tomp: \"mcp__entwurf_bridge_entwurf_v\","],
|
|
47
|
+
"replace": ["\tomp: \"mcp__entwurf_bridge_entwurf_v2\","],
|
|
48
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
49
|
+
"timeoutSeconds": 300,
|
|
50
|
+
"signature": "[QK:FRESHCALL-OMP-CALLBACK-TOOL-DIALECT]",
|
|
51
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"claim": "FRESHCALL-OMP-XDEV-FAIL-CLOSED",
|
|
55
|
+
"title": "the callback-callable axis inverted from `must prove false` to `refuse only on explicit true`. The vendor default IS true, so a host that never set tools.xdev preflights green and the fresh call opens a window whose model cannot see the callback tool's schema at all — a sibling that can never name itself, with a successful launch receipt in the caller's hand",
|
|
56
|
+
"subject": "pi-extensions/lib/omp-fresh-preflight.ts",
|
|
57
|
+
"find": [
|
|
58
|
+
"\tif (readOmpConfigFlag(agentDir, \"tools\", \"xdev\") !== false) return \"omp-callback-tool-uncallable\";"
|
|
59
|
+
],
|
|
60
|
+
"replace": [
|
|
61
|
+
"\tif (readOmpConfigFlag(agentDir, \"tools\", \"xdev\") === true) return \"omp-callback-tool-uncallable\";"
|
|
62
|
+
],
|
|
63
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
64
|
+
"timeoutSeconds": 300,
|
|
65
|
+
"signature": "[QK:FRESHCALL-OMP-XDEV-FAIL-CLOSED]",
|
|
66
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"claim": "FRESHCALL-OMP-AGENT-DIR-REFUSES-PI-KNOB",
|
|
70
|
+
"title": "an inherited PI_CODING_AGENT_DIR taken as a lookup instead of a refusal. omp is a pi fork sharing that name, so the preflight would check units under entwurf's own pi sandbox and report green about a directory no live omp reads — the ledger M6 collision, resolved by guessing",
|
|
71
|
+
"subject": "pi-extensions/lib/omp-fresh-preflight.ts",
|
|
72
|
+
"find": [
|
|
73
|
+
"\tif (typeof env.PI_CODING_AGENT_DIR === \"string\" && env.PI_CODING_AGENT_DIR.length > 0) return null;"
|
|
74
|
+
],
|
|
75
|
+
"replace": [
|
|
76
|
+
"\tif (typeof env.PI_CODING_AGENT_DIR === \"string\" && env.PI_CODING_AGENT_DIR.length > 0)\n\t\treturn path.resolve(env.PI_CODING_AGENT_DIR);"
|
|
77
|
+
],
|
|
78
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
79
|
+
"timeoutSeconds": 300,
|
|
80
|
+
"signature": "[QK:FRESHCALL-OMP-AGENT-DIR-REFUSES-PI-KNOB]",
|
|
81
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"claim": "OMP-PREFLIGHT-XDEV-ORACLE",
|
|
85
|
+
"title": "the reproduced config reader drifting from the shipped python leaf — a key matched at ANY depth inside the section, so `tools.nested.xdev: false` reads as `tools.xdev: false`. This is the real defect the agreement gate caught on its first run: a fail-OPEN misread that preflights green off a config which never set the flag",
|
|
86
|
+
"subject": "pi-extensions/lib/omp-fresh-preflight.ts",
|
|
87
|
+
"find": ["\t\tif (indent !== childIndent) continue; // a grandchild, or a mis-indented line: not our key"],
|
|
88
|
+
"replace": ["\t\tif (false && indent !== childIndent) continue;"],
|
|
89
|
+
"gate": ["bash", "run.sh", "check-omp-fresh-preflight"],
|
|
90
|
+
"timeoutSeconds": 300,
|
|
91
|
+
"signature": "[QK:OMP-PREFLIGHT-XDEV-ORACLE]",
|
|
92
|
+
"signatureSource": "scripts/check-omp-fresh-preflight.ts"
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
"claim": "OMP-PREFLIGHT-AGENT-DIR-ORACLE",
|
|
96
|
+
"title": "the reproduced agent-dir resolver diverging from the installer's own shell oracle on the profile axis — OMP_PROFILE honoured without its name grammar, so a profile the shell refuses resolves here and the two halves of the omp lane address different stores while both look correct",
|
|
97
|
+
"subject": "pi-extensions/lib/omp-fresh-preflight.ts",
|
|
98
|
+
"find": ["\t\tif (!PROFILE_NAME_RE.test(ompProfile)) return null;"],
|
|
99
|
+
"replace": ["\t\tif (false && !PROFILE_NAME_RE.test(ompProfile)) return null;"],
|
|
100
|
+
"gate": ["bash", "run.sh", "check-omp-fresh-preflight"],
|
|
101
|
+
"timeoutSeconds": 300,
|
|
102
|
+
"signature": "[QK:OMP-PREFLIGHT-AGENT-DIR-ORACLE]",
|
|
103
|
+
"signatureSource": "scripts/check-omp-fresh-preflight.ts"
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"claim": "FRESHCALL-IDENTITY-SCRUB",
|
|
107
|
+
"title": "the inherited pi identity carrier left unscrubbed at the launch seam. A tmux server started from a shell that exported PI_SESSION_ID hands that value to every window it opens (measured), and the sibling's own MCP child reads the stale pair as its authoritative identity — so a fresh citizen calls home as someone else, confidently",
|
|
108
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
109
|
+
"find": ["\t\t...SCRUBBED_INHERITED_ENV.flatMap((assignment) => [\"-e\", assignment]),"],
|
|
110
|
+
"replace": [""],
|
|
111
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
112
|
+
"timeoutSeconds": 300,
|
|
113
|
+
"signature": "[QK:FRESHCALL-IDENTITY-SCRUB]",
|
|
114
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"claim": "FRESHCALL-BACKEND-SET-SURFACE-PARITY-SKILL",
|
|
118
|
+
"title": "a backend added to the composition and both schema surfaces but not to the operator skill — the third public surface step 9 names, and the one that had no gate at all. The skill is what an operator reads to decide what can be opened, so a stale list makes the backend unreachable in practice exactly the way a missing enum value makes it unreachable in schema",
|
|
119
|
+
"subject": ".claude/skills/entwurf-dev/SKILL.md",
|
|
120
|
+
"find": ["backend는 정확히 `pi | claude-code | copilot | omp`이고"],
|
|
121
|
+
"replace": ["backend는 정확히 `pi | claude-code | copilot`이고"],
|
|
122
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
123
|
+
"timeoutSeconds": 300,
|
|
124
|
+
"signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY-SKILL]",
|
|
125
|
+
"signatureSource": "test/fresh-call-surfaces.contract.test.ts"
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"claim": "FRESHCALL-OMP-ARGV-BOOTSTRAP-FLAG",
|
|
129
|
+
"title": "the positional first-turn prompt put back on the omp argv beside the bootstrap flag — the exact shape the first Bundle C candidate shipped. `[LIVE 2026-08-30]` it opens a window whose turn starts ~830ms BEFORE the callback tool exists, and the sibling answers the literal text `ACK` with zero tool calls. It parses, it launches, and the caller times out at 240s: the failure is invisible to anything that only checks that argv is well-formed",
|
|
130
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
131
|
+
"find": [
|
|
132
|
+
"\t\t\treturn [`--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model, \"--approval-mode\", \"yolo\"];"
|
|
133
|
+
],
|
|
134
|
+
"replace": [
|
|
135
|
+
"\t\t\treturn [composition.prompt, `--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model, \"--approval-mode\", \"yolo\"];"
|
|
136
|
+
],
|
|
137
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
138
|
+
"timeoutSeconds": 300,
|
|
139
|
+
"signature": "[QK:FRESHCALL-OMP-ARGV-BOOTSTRAP-FLAG]",
|
|
140
|
+
"signatureSource": "test/mux-fresh-call.test.ts"
|
|
141
|
+
},
|
|
142
|
+
{
|
|
143
|
+
"claim": "OMP-BOOTSTRAP-FLAG-AGREES",
|
|
144
|
+
"title": "the installed unit renamed its registered flag while the launcher keeps sending the old one. The unit still loads, still mints, still shows the garden id — and every fresh call at omp silently becomes a manual session that sits there with no task, because `getFlag` answers only for flags THIS extension registered. Two halves that ship in different directories and cannot import each other is exactly where a constant drifts",
|
|
145
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
146
|
+
"find": ["export const OMP_BOOTSTRAP_FLAG = \"entwurf-bootstrap\";"],
|
|
147
|
+
"replace": ["export const OMP_BOOTSTRAP_FLAG = \"entwurf-fresh-bootstrap\";"],
|
|
148
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
149
|
+
"timeoutSeconds": 300,
|
|
150
|
+
"signature": "[QK:OMP-BOOTSTRAP-FLAG-AGREES]",
|
|
151
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"claim": "OMP-BOOTSTRAP-READY-NEEDS-BOTH",
|
|
155
|
+
"title": "readiness decided from the tool REGISTRY alone, dropping the enabled-tools half. A tool can be registered and not enabled, and a prompt can only call an enabled one — so this sends the callback-only prompt into a window where the model still cannot make the call, which is the same 830ms race the positional prompt lost, moved one layer inward",
|
|
156
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
157
|
+
"find": ["\treturn registered && active.includes(OMP_BOOTSTRAP_CALLBACK_TOOL);"],
|
|
158
|
+
"replace": ["\treturn registered;"],
|
|
159
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
160
|
+
"timeoutSeconds": 300,
|
|
161
|
+
"signature": "[QK:OMP-BOOTSTRAP-READY-NEEDS-BOTH]",
|
|
162
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
"claim": "OMP-BOOTSTRAP-CALLBACK-ONLY",
|
|
166
|
+
"title": "the task folded back into the stage-one prompt, so the sibling is asked to call back AND to work in one message. This is the prompt the failed LIVE actually ran, minus the missing tool: a competing goal beside the callback is what the two-stage split exists to remove, and nothing about argv or readiness would notice it coming back",
|
|
167
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
168
|
+
"find": ["\t\t\tsend(buildOmpCallbackOnlyPrompt({ target: payload.target, nonce: payload.nonce }));"],
|
|
169
|
+
"replace": [
|
|
170
|
+
"\t\t\tsend(`${buildOmpCallbackOnlyPrompt({ target: payload.target, nonce: payload.nonce })}\\n\\n${payload.task}`);"
|
|
171
|
+
],
|
|
172
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
173
|
+
"timeoutSeconds": 300,
|
|
174
|
+
"signature": "[QK:OMP-BOOTSTRAP-CALLBACK-ONLY]",
|
|
175
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
176
|
+
},
|
|
177
|
+
{
|
|
178
|
+
"claim": "OMP-BOOTSTRAP-ISERROR-EXACT-FALSE",
|
|
179
|
+
"title": "the success predicate loosened from `isError === false` to `isError === true` being the only failure, so a result whose isError is ABSENT or non-boolean releases the caller's task. The happy path is unchanged and every LIVE run still passes; what changes is that a malformed or partial result now counts as a callback that succeeded",
|
|
180
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
181
|
+
"find": ["\t\t\tif (event?.isError !== false) {"],
|
|
182
|
+
"replace": ["\t\t\tif (event?.isError === true) {"],
|
|
183
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
184
|
+
"timeoutSeconds": 300,
|
|
185
|
+
"signature": "[QK:OMP-BOOTSTRAP-ISERROR-EXACT-FALSE]",
|
|
186
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"claim": "OMP-BOOTSTRAP-NO-ARBITRARY-CARRIER",
|
|
190
|
+
"title": "the decoder's unknown-key refusal removed, so the one flag a caller can put arbitrary bytes into starts silently ignoring whatever it does not recognise. Every valid payload still decodes identically, so no behavioural test moves — but `what the launcher meant` and `what the unit acts on` have stopped being the same closed set, which is the property that keeps this from becoming a general carrier",
|
|
191
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
192
|
+
"find": ["\t\tif (!BOOTSTRAP_KEYS.has(key)) return { ok: false, reason: \"payload-unknown-key\" };"],
|
|
193
|
+
"replace": [
|
|
194
|
+
"\t\tif (!BOOTSTRAP_KEYS.has(key) && key.startsWith(\"__\")) return { ok: false, reason: \"payload-unknown-key\" };"
|
|
195
|
+
],
|
|
196
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
197
|
+
"timeoutSeconds": 300,
|
|
198
|
+
"signature": "[QK:OMP-BOOTSTRAP-NO-ARBITRARY-CARRIER]",
|
|
199
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
"claim": "OMP-BOOTSTRAP-RESULT-ARMS-ONLY",
|
|
203
|
+
"title": "the task sent from inside the tool_result handler again, instead of at the turn_end boundary. `[LIVE 2026-08-30]` this is the exact shape that failed: the hook log showed armed/ready/callback-observed/released, the release predicate was provably correct, and the task still never appeared in the session — because that handler runs while the callback turn is streaming. Every static contract about correlation and readiness stays green while the product delivers nothing",
|
|
204
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
205
|
+
"find": [
|
|
206
|
+
"\t\t\tlog(\"INFO\", `bootstrap-released nonce=${payload.nonce} toolCallId=${callId}: task armed for the next turn_end`);"
|
|
207
|
+
],
|
|
208
|
+
"replace": [
|
|
209
|
+
"\t\t\tlog(\"INFO\", `bootstrap-released nonce=${payload.nonce} toolCallId=${callId}: task armed for the next turn_end`);\n\t\t\tphase = \"task-sent\";\n\t\t\tsend(payload.task);"
|
|
210
|
+
],
|
|
211
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
212
|
+
"timeoutSeconds": 300,
|
|
213
|
+
"signature": "[QK:OMP-BOOTSTRAP-RESULT-ARMS-ONLY]",
|
|
214
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"claim": "OMP-BOOTSTRAP-NO-EXPLICIT-DELIVERY",
|
|
218
|
+
"title": "an explicit delivery option put back on the send. `[source]` omitted `deliverAs` starts a turn when idle and steers while streaming; an EXPLICIT one queues without starting a turn in either state (`oh-my-pi v18.0.0 session/agent-session.ts:6511-6513`). `[LIVE 2026-08-30]` the queued form was measured to never become a message at all, three seconds before the Bundle B doorbell's omitted-option send landed and started a turn in the SAME session. Nothing about argv, readiness or correlation notices this",
|
|
219
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
220
|
+
"find": ["\t\t\tpi.sendUserMessage(content);"],
|
|
221
|
+
"replace": ["\t\t\tpi.sendUserMessage(content, { deliverAs: \"followUp\" });"],
|
|
222
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
223
|
+
"timeoutSeconds": 300,
|
|
224
|
+
"signature": "[QK:OMP-BOOTSTRAP-NO-EXPLICIT-DELIVERY]",
|
|
225
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
"claim": "OMP-BOOTSTRAP-ONE-TASK",
|
|
229
|
+
"title": "the turn_end guard widened to admit an already-spent bootstrap, so every later turn of the session re-delivers the caller's task. The first turn is identical and a LIVE acceptance that only checks `the task arrived` still passes; what changes is that a sibling working for ten turns receives its opening instruction ten times",
|
|
230
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
231
|
+
"find": ["\t\t\tif (phase !== \"released\") return;"],
|
|
232
|
+
"replace": ["\t\t\tif (phase !== \"released\" && phase !== \"task-sent\") return;"],
|
|
233
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
234
|
+
"timeoutSeconds": 300,
|
|
235
|
+
"signature": "[QK:OMP-BOOTSTRAP-ONE-TASK]",
|
|
236
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
237
|
+
},
|
|
238
|
+
{
|
|
239
|
+
"claim": "OMP-BOOTSTRAP-RELEASED-IS-INVALIDATABLE",
|
|
240
|
+
"title": "`released` made un-invalidatable, so a bootstrap whose session is replaced by `/new`, a fork or a resume BETWEEN the callback result and the next turn_end still fires its task — into a session the caller never opened and cannot address. The window between those two events is small and the failure is invisible until the operator's own next session receives someone else's instruction",
|
|
241
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
242
|
+
"find": [
|
|
243
|
+
"\t\t\t// `released` is invalidatable ON PURPOSE: between the callback result and the next\n\t\t\t// turn_end the session can be replaced by `/new`, a fork or a resume, and the\n\t\t\t// caller's task must die with the session it was addressed to.\n\t\t\tif (isFinal()) return;"
|
|
244
|
+
],
|
|
245
|
+
"replace": ["\t\t\tif (phase === \"released\" || isFinal()) return;"],
|
|
246
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
247
|
+
"timeoutSeconds": 300,
|
|
248
|
+
"signature": "[QK:OMP-BOOTSTRAP-RELEASED-IS-INVALIDATABLE]",
|
|
249
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
250
|
+
},
|
|
251
|
+
{
|
|
252
|
+
"claim": "OMP-BOOTSTRAP-SESSION-FENCE",
|
|
253
|
+
"title": "the native session id dropped from the event fence, leaving only `mode === \"tui\"`. Tool and turn events carry no session id of their own, so after a `/new` the previous caller's bootstrap would start accepting the REPLACEMENT session's tool results and deliver its task there. The happy path — one launch, one session, no switch — is completely unaffected",
|
|
254
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
255
|
+
"find": ["\treturn typeof id === \"string\" && id === boundSessionId;"],
|
|
256
|
+
"replace": ["\tvoid boundSessionId;\n\treturn typeof id === \"string\";"],
|
|
257
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
258
|
+
"timeoutSeconds": 300,
|
|
259
|
+
"signature": "[QK:OMP-BOOTSTRAP-SESSION-FENCE]",
|
|
260
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
261
|
+
},
|
|
262
|
+
{
|
|
263
|
+
"claim": "OMP-BOOTSTRAP-SAME-ID-SWITCH-INVALIDATES",
|
|
264
|
+
"title": "the native-id comparison put back INSIDE the one function that owns the epoch rule, exactly as the frozen Bundle C candidate had it. The vendor emits session_switch(reason:\"resume\") on the same-file reload path WITHOUT changing the native id and replaces the transcript right after (agent-session.ts:7986-7988 computes switchingToDifferentSession, :8071-8078 emits regardless), so an id-conditional rule lets a waiting, callback-sent or released bootstrap survive a real epoch change wearing the old id. Note what does NOT catch this: on the wired onBirthEdge path the pre-envelope call passes no id at all and still ends the epoch, so the defence in depth added for O-D1r masks the mutation there — it is the direct-drive cell, which reaches the rule with a real id the way a healthy edge does, that kills it",
|
|
265
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
266
|
+
"find": ["\tif (!bootstrapConsumed || activeBootstrap === null) return;\n"],
|
|
267
|
+
"replace": [
|
|
268
|
+
"\tif (!bootstrapConsumed || activeBootstrap === null) return;\n\tif (nativeSessionId !== null && activeBootstrap.sessionId === nativeSessionId) return;\n"
|
|
269
|
+
],
|
|
270
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
271
|
+
"timeoutSeconds": 300,
|
|
272
|
+
"signature": "[QK:OMP-BOOTSTRAP-SAME-ID-SWITCH-INVALIDATES]",
|
|
273
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
274
|
+
},
|
|
275
|
+
{
|
|
276
|
+
"claim": "OMP-BOOTSTRAP-REFUSES-UNCANCELLABLE-TIMER",
|
|
277
|
+
"title": "a silent global-timer fallback restored under the creator-owned seam. A vendor build with no ctx.setTimeout/ctx.clearTimer would arm anyway on a raw setTimeout that belongs to no session registry and that clearTimer cannot reach — a 100ms poll running inside the operator's TUI for the life of the process, surviving the disposal of the session that scheduled it. It is invisible to every behavioural test on a COMPLETE vendor context, because on v18.0.0 the fallback is never taken",
|
|
278
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
279
|
+
"find": ["\tconst timers = creatorOwnedTimers(ctx);\n"],
|
|
280
|
+
"replace": [
|
|
281
|
+
"\tconst timers: OmpBootstrapTimers | null =\n\t\tcreatorOwnedTimers(ctx) ??\n\t\t({\n\t\t\tset: (fn: () => void, ms: number) => setTimeout(fn, ms),\n\t\t\tclear: (handle: unknown) => {\n\t\t\t\tclearTimeout(handle as ReturnType<typeof setTimeout>);\n\t\t\t},\n\t\t\tnow: () => Date.now(),\n\t\t} satisfies OmpBootstrapTimers);\n"
|
|
282
|
+
],
|
|
283
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
284
|
+
"timeoutSeconds": 300,
|
|
285
|
+
"signature": "[QK:OMP-BOOTSTRAP-REFUSES-UNCANCELLABLE-TIMER]",
|
|
286
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
287
|
+
},
|
|
288
|
+
{
|
|
289
|
+
"claim": "OMP-BOOTSTRAP-EPOCH-ENDS-BEFORE-ENVELOPE",
|
|
290
|
+
"title": "the epoch-ending call moved back behind the envelope, which is the pre-O-D1r shape. onBirthEdge has two early exits before it ever reaches startOmpBootstrap — a refused envelope and a throwing upsert — so ending the epoch only from inside startOmpBootstrap makes the rule conditional on the LATER edge succeeding. A same-id session_switch that takes either exit then leaves a released bootstrap alive, and it still passes both fences in ompBootstrapCtxAccepts, so the previous caller's task lands at the next turn_end of a session the caller never opened. Every healthy edge is unaffected, which is why a review found this by reading the bail paths rather than by running anything",
|
|
291
|
+
"subject": "pi-extensions/meta-bridge-omp.ts",
|
|
292
|
+
"find": ["\tendBootstrapEpochOnLaterEdge(edge, null);\n\n\tconst envelope = readBirthEnvelope(ctx);"],
|
|
293
|
+
"replace": ["\tconst envelope = readBirthEnvelope(ctx);"],
|
|
294
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
295
|
+
"timeoutSeconds": 300,
|
|
296
|
+
"signature": "[QK:OMP-BOOTSTRAP-EPOCH-ENDS-BEFORE-ENVELOPE]",
|
|
297
|
+
"signatureSource": "test/omp-fresh-bootstrap.contract.test.ts"
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
}
|