@junghanacs/entwurf 0.22.0 → 0.23.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 +4 -1
- package/BASELINE.md +1 -0
- package/CHANGELOG.md +514 -0
- package/DELIVERY.md +10 -2
- package/README.md +43 -4
- package/VERIFY.md +47 -0
- package/docs/acp-backend-rail.md +96 -17
- package/docs/setup-clean-host.md +11 -1
- package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +39 -40
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/tool-surface.js +2 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-declaration.js +609 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/codex-fresh-preflight.js +95 -56
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-control-rpc.js +40 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-fact-provider.js +6 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-facts.js +7 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peer-observe.js +67 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-peers-render.js +9 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-self-address.js +24 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-contract.js +2 -2
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-lock.js +1 -1
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +423 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +98 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +1018 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-placement.js +213 -0
- package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +46 -273
- package/mcp/entwurf-bridge/dist/scripts/peer-facts.js +109 -0
- package/mcp/entwurf-bridge/src/index.ts +41 -41
- package/mcp/entwurf-bridge/tsconfig.build.json +1 -0
- package/package.json +9 -8
- package/pi-extensions/entwurf-control.ts +91 -52
- package/pi-extensions/lib/acp/acp-client.ts +3 -3
- package/pi-extensions/lib/acp/backend-adapter.ts +3 -3
- package/pi-extensions/lib/acp/backend.ts +4 -4
- package/pi-extensions/lib/acp/event-mapper.ts +5 -5
- package/pi-extensions/lib/acp/tool-surface.ts +2 -1
- package/pi-extensions/lib/codex-declaration.js +612 -0
- package/pi-extensions/lib/codex-fresh-preflight.ts +107 -51
- package/pi-extensions/lib/entwurf-control-rpc.ts +46 -0
- package/pi-extensions/lib/entwurf-fact-provider.ts +13 -2
- package/pi-extensions/lib/entwurf-facts.ts +14 -1
- package/pi-extensions/lib/entwurf-peer-observe.ts +72 -2
- package/pi-extensions/lib/entwurf-peers-render.ts +9 -1
- package/pi-extensions/lib/entwurf-self-address.ts +33 -0
- package/pi-extensions/lib/entwurf-v2-contract.ts +2 -2
- package/pi-extensions/lib/entwurf-v2-lock.ts +1 -1
- package/pi-extensions/lib/entwurf-v2-runner.ts +1 -1
- package/pi-extensions/lib/fresh-call-composition.ts +493 -0
- package/pi-extensions/lib/fresh-call-dispatch.ts +142 -0
- package/pi-extensions/lib/herdr-fresh-call.ts +1378 -0
- package/pi-extensions/lib/herdr-placement.ts +276 -0
- package/pi-extensions/lib/mux-fresh-call.ts +95 -301
- package/run.sh +588 -204
- package/scripts/check-acp-usage-accounting.ts +9 -9
- package/scripts/check-codex-birth-hook.ts +187 -0
- package/scripts/check-entwurf-control-rpc.ts +138 -0
- package/scripts/check-entwurf-fact-provider.ts +4 -2
- package/scripts/check-entwurf-peers-surface.ts +3 -1
- package/scripts/check-entwurf-self-address.ts +68 -0
- package/scripts/check-fresh-call-dispatch.ts +301 -0
- package/scripts/check-gate-qualification.ts +17 -4
- package/scripts/check-herdr-activation.ts +1293 -0
- package/scripts/check-herdr-fresh-call.ts +1250 -0
- package/scripts/check-herdr-placement.ts +383 -0
- package/scripts/check-herdr-plugin-build.ts +842 -0
- package/scripts/check-herdr-plugin-profile.ts +371 -0
- package/scripts/check-herdr-plugin.ts +523 -0
- package/scripts/check-herdr-runtime-bootstrap.ts +1264 -0
- package/scripts/check-herdr-sandbox.ts +456 -0
- package/scripts/check-herdr-supply.ts +184 -0
- package/scripts/check-mux-launcher-fence.ts +138 -0
- package/scripts/check-peer-facts.ts +331 -0
- package/scripts/check-pi-launch.ts +358 -0
- package/scripts/check-release-gate-outcomes.ts +19 -0
- package/scripts/check-typing-call-fence.ts +296 -0
- package/scripts/codex-birth-doctor.sh +159 -16
- package/scripts/codex-birth-install.sh +178 -72
- package/scripts/codex-birth-uninstall.sh +162 -7
- package/scripts/fixtures/herdr-supply.json +29 -0
- package/scripts/herdr-activation.mjs +536 -0
- package/scripts/herdr-plugin-activate.mjs +270 -0
- package/scripts/herdr-plugin-deactivate.mjs +193 -0
- package/scripts/herdr-runtime.mjs +1203 -0
- package/scripts/install-herdr-ci.sh +96 -0
- package/scripts/inventory-verification-surface.ts +86 -10
- package/scripts/lib/codex-fresh-live-protocol.ts +2 -2
- package/scripts/lib/tree-digest.ts +97 -0
- package/scripts/meta-bridge-install.sh +19 -2
- package/scripts/meta-bridge-state.py +167 -11
- package/scripts/mutants/codex-caller-seat.json +6 -8
- package/scripts/mutants/codex-native.json +195 -29
- package/scripts/mutants/control-socket-disconnect.json +57 -0
- package/scripts/mutants/fresh-call-dispatch.json +154 -0
- package/scripts/mutants/herdr-activation.json +305 -0
- package/scripts/mutants/herdr-fresh-call.json +448 -0
- package/scripts/mutants/herdr-placement.json +161 -0
- package/scripts/mutants/herdr-plugin-build.json +160 -0
- package/scripts/mutants/herdr-plugin-profile.json +202 -0
- package/scripts/mutants/herdr-plugin.json +133 -0
- package/scripts/mutants/herdr-runtime-bootstrap.json +411 -0
- package/scripts/mutants/herdr-supply.json +133 -0
- package/scripts/mutants/meta-hook-session-switch.json +2 -2
- package/scripts/mutants/mux-fresh-call.json +104 -17
- package/scripts/mutants/mux-launcher-fence.json +13 -0
- package/scripts/mutants/omp-fresh.json +4 -4
- package/scripts/mutants/peer-facts.json +98 -0
- package/scripts/mutants/pi-launch.json +113 -0
- package/scripts/mutants/resume-args.json +6 -6
- package/scripts/mutants/self-address.json +33 -0
- package/scripts/mutants/typing-call-fence.json +17 -0
- package/scripts/mutants/v2-surface.json +2 -2
- package/scripts/mutants/v2-visible-resume.json +17 -17
- package/scripts/peer-facts.ts +120 -0
- package/scripts/register-pi-package.py +8 -0
- package/scripts/register-pi-provider.py +88 -12
- package/scripts/smoke-acp-raw-turn-live.ts +1 -1
- package/scripts/smoke-codex-birth.sh +281 -12
- package/scripts/smoke-entwurf-v2-matrix-live.ts +1 -1
- package/scripts/smoke-herdr-fresh-call-live.ts +1027 -0
- package/scripts/smoke-herdr-plugin-build-live.ts +543 -0
- package/scripts/smoke-herdr-raw-install-live.sh +849 -0
- package/scripts/tsconfig.json +5 -0
- package/scripts/check-entwurf-facts.ts +0 -385
- package/scripts/check-entwurf-resume-args.ts +0 -122
- package/scripts/check-entwurf-v2-decider.ts +0 -657
- package/scripts/check-entwurf-v2-lock.ts +0 -371
- package/scripts/check-entwurf-v2-mailbox.ts +0 -261
- package/scripts/check-entwurf-v2-matrix.ts +0 -401
- package/scripts/check-entwurf-v2-native-push.ts +0 -221
- package/scripts/check-entwurf-v2-release.ts +0 -151
- package/scripts/check-entwurf-v2-runner.ts +0 -448
- package/scripts/check-entwurf-v2-send-fallback.ts +0 -350
- package/scripts/check-entwurf-v2-send.ts +0 -458
- package/scripts/check-entwurf-v2-visible-resume.ts +0 -445
- package/scripts/check-socket-discovery.ts +0 -401
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
8
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
9
9
|
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
10
10
|
"replace": ["\t\t\treturn [\"--entwurf-control\", composition.prompt, \"--model\", model];"],
|
|
11
11
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
{
|
|
17
17
|
"claim": "FRESHCALL-CLAUDE-ARGV-EQUALS-FORM",
|
|
18
18
|
"title": "claude-code goes back to the variadic space form, which swallows the prompt as an option value",
|
|
19
|
-
"subject": "pi-extensions/lib/
|
|
19
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
20
20
|
"find": [
|
|
21
21
|
"\t\t\treturn [composition.prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
22
22
|
],
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
34
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
35
35
|
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
36
36
|
"replace": ["\t\t\treturn [composition.prompt, \"--entwurf-control\"];"],
|
|
37
37
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -42,7 +42,7 @@
|
|
|
42
42
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
45
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
46
46
|
"find": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", \"--model\", model];"],
|
|
47
47
|
"replace": ["\t\t\treturn [composition.prompt, \"--entwurf-control\", `--model=${model}`];"],
|
|
48
48
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
{
|
|
54
54
|
"claim": "FRESHCALL-CLAUDE-MODEL-ARGV",
|
|
55
55
|
"title": "Claude Code drops the explicit model token and silently resolves its ambient Opus default again",
|
|
56
|
-
"subject": "pi-extensions/lib/
|
|
56
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
57
57
|
"find": [
|
|
58
58
|
"\t\t\treturn [composition.prompt, `--allowedTools=${FRESH_CALL_CALLBACK_TOOL[\"claude-code\"]}`, `--model=${model}`];"
|
|
59
59
|
],
|
|
@@ -66,7 +66,7 @@
|
|
|
66
66
|
{
|
|
67
67
|
"claim": "FRESHCALL-CALLBACK-PRECEDES-TASK",
|
|
68
68
|
"title": "the task is framed before the callback instruction, so a sibling that stalls in the task never names itself",
|
|
69
|
-
"subject": "pi-extensions/lib/
|
|
69
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
70
70
|
"find": ["\t\t`FIRST ACTION, before reading files or anything else: call ${tool} with ` +"],
|
|
71
71
|
"replace": ["\t\t`FINAL ACTION, after completing the task: call ${tool} with ` +"],
|
|
72
72
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -123,7 +123,7 @@
|
|
|
123
123
|
"title": "one surface drops the optional cwd from its schema, so cross-repo fresh works from pi and silently cannot exist from the MCP bridge",
|
|
124
124
|
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
125
125
|
"find": [
|
|
126
|
-
"\t\tcwd: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Optional literal ABSOLUTE path of an existing directory to start the sibling in (cross-repo fresh).
|
|
126
|
+
"\t\tcwd: z\n\t\t\t.string()\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Optional literal ABSOLUTE path of an existing directory to start the sibling in (cross-repo fresh). Omit or pass \\\"\\\" to start where the CALLER is — this agent's own cwd on BOTH rails, or for a Codex caller its own record directory, because this bridge is the app-server's child and that process's directory is not the caller's. Taken exactly as given: no trim, no realpath, no project-name resolution. '#' is refused on the tmux rail only, because tmux format-expands a start directory; inside herdr it is an ordinary path character. The receipt echoes the directory that was REQUESTED or the caller record it came from, never an observation of where the pane landed.\",\n\t\t\t),\n"
|
|
127
127
|
],
|
|
128
128
|
"replace": [""],
|
|
129
129
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -239,7 +239,7 @@
|
|
|
239
239
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
242
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
243
243
|
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
244
244
|
"replace": ["\t\t\treturn [\"copilot\", \"-p\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
245
245
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
253
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
254
254
|
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
255
255
|
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--yolo\"];"],
|
|
256
256
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -261,7 +261,7 @@
|
|
|
261
261
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
264
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
265
265
|
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
266
266
|
"replace": [
|
|
267
267
|
"\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--allow-tool=entwurf-bridge(entwurf_v2)\"];"
|
|
@@ -274,7 +274,7 @@
|
|
|
274
274
|
{
|
|
275
275
|
"claim": "FRESHCALL-COPILOT-CALLBACK-TOOL",
|
|
276
276
|
"title": "the Copilot callback names Claude Code's `mcp__server__tool` spelling — a dialect copied instead of measured, and the whole first turn is spent looking for a tool that is not there",
|
|
277
|
-
"subject": "pi-extensions/lib/
|
|
277
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
278
278
|
"find": ["\tcopilot: \"entwurf-bridge-entwurf_v2\","],
|
|
279
279
|
"replace": ["\tcopilot: \"mcp__entwurf-bridge__entwurf_v2\","],
|
|
280
280
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -420,7 +420,7 @@
|
|
|
420
420
|
{
|
|
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
|
-
"subject": "pi-extensions/lib/
|
|
423
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
424
424
|
"find": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model, \"--yolo\"];"],
|
|
425
425
|
"replace": ["\t\t\treturn [\"copilot\", \"--interactive\", composition.prompt, \"--model\", model];"],
|
|
426
426
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -512,7 +512,7 @@
|
|
|
512
512
|
"title": "one surface drops the optional seat from its schema, so opening a sibling in the operator's project session works from pi and silently cannot exist from the MCP bridge",
|
|
513
513
|
"subject": "mcp/entwurf-bridge/src/index.ts",
|
|
514
514
|
"find": [
|
|
515
|
-
"\t\tplacement: z\n\t\t\t.object({\n\t\t\t\ttmuxSession: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"EXACT name of an EXISTING session on this agent's own tmux server. Nothing is created: an absent session is refused as tmux-session-missing, and a name outside [A-Za-z0-9][A-Za-z0-9_-]* as tmux-session-name-invalid.\",\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Optional expert seat override: open the sibling in ONE EXISTING tmux session of this agent's own server, and it always wins. When omitted the seat follows the CALLER, never the backend being opened: a Codex CALLER opens beside its own TUI pane, matched by thread-id in that pane's terminal title (0 or 2+ matching panes refuse, never fall back); every other caller opens in its own session. A pane title is a placement input only — never an address, liveness or delivery fact. Nothing is ever created. Independent of cwd; neither is inferred from the other. The receipt reports the selected name (absent for the caller-pane rule, which observed a session rather than requesting a name), its source, and resolved target session id.\",\n\t\t\t),\n"
|
|
515
|
+
"\t\tplacement: z\n\t\t\t.object({\n\t\t\t\ttmuxSession: z\n\t\t\t\t\t.string()\n\t\t\t\t\t.describe(\n\t\t\t\t\t\t\"EXACT name of an EXISTING session on this agent's own tmux server. Nothing is created: an absent session is refused as tmux-session-missing, and a name outside [A-Za-z0-9][A-Za-z0-9_-]* as tmux-session-name-invalid.\",\n\t\t\t\t\t),\n\t\t\t})\n\t\t\t.optional()\n\t\t\t.describe(\n\t\t\t\t\"Optional expert seat override, TMUX ONLY: open the sibling in ONE EXISTING tmux session of this agent's own server, and it always wins. When omitted the seat follows the CALLER, never the backend being opened: a Codex CALLER opens beside its own TUI pane, matched by thread-id in that pane's terminal title (0 or 2+ matching panes refuse, never fall back); every other caller opens in its own session. A pane title is a placement input only — never an address, liveness or delivery fact. Nothing is ever created. Inside herdr this field is refused by name — placement there belongs to herdr, and a tmux session name would silently place the sibling somewhere else. Independent of cwd; neither is inferred from the other. The receipt reports the selected name (absent for the caller-pane rule, which observed a session rather than requesting a name), its source, and resolved target session id.\",\n\t\t\t),\n"
|
|
516
516
|
],
|
|
517
517
|
"replace": [""],
|
|
518
518
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -520,11 +520,61 @@
|
|
|
520
520
|
"signature": "[QK:FRESHCALL-PLACEMENT-SURFACE-PARITY]",
|
|
521
521
|
"signatureSource": "test/fresh-call-surfaces.contract.test.ts"
|
|
522
522
|
},
|
|
523
|
+
{
|
|
524
|
+
"claim": "FRESHCOMP-NODE-ONLY-IMPORTS",
|
|
525
|
+
"title": "the composition leaf takes a repo-local import again — one is all it takes for the tmux rail to be back behind a rail that has no tmux",
|
|
526
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
527
|
+
"find": ["import { randomBytes } from \"node:crypto\";"],
|
|
528
|
+
"replace": ["import { randomBytes } from \"node:crypto\";\nimport { runTmux } from \"./mux-placement.ts\";"],
|
|
529
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
530
|
+
"timeoutSeconds": 120,
|
|
531
|
+
"signature": "[QK:FRESHCOMP-NODE-ONLY-IMPORTS]",
|
|
532
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
533
|
+
},
|
|
534
|
+
{
|
|
535
|
+
"claim": "FRESHCOMP-TMUX-OPENING-LINE",
|
|
536
|
+
"title": "the extraction quietly reworded the tmux rail's first sentence — the sibling is told where it is by a refactor rather than by a measurement",
|
|
537
|
+
"subject": "pi-extensions/lib/mux-fresh-call.ts",
|
|
538
|
+
"find": ["\t\"You are a fresh visible citizen that entwurf opened in the operator's tmux session.\";"],
|
|
539
|
+
"replace": ["\t\"You are a fresh visible citizen that entwurf opened in a terminal pane.\";"],
|
|
540
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
541
|
+
"timeoutSeconds": 120,
|
|
542
|
+
"signature": "[QK:FRESHCOMP-TMUX-OPENING-LINE]",
|
|
543
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
"claim": "FRESHCOMP-RAIL-OWNS-PLACEMENT-SENTENCE",
|
|
547
|
+
"title": "the leaf invents a placement sentence when the rail supplies none — a default that is true on one rail is a lie on the other",
|
|
548
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
549
|
+
"find": [
|
|
550
|
+
"\tif (params.openingLine.length === 0) {\n\t\tthrow new Error(\"fresh-call composition: openingLine is empty — the rail must state where it placed the sibling\");\n\t}"
|
|
551
|
+
],
|
|
552
|
+
"replace": [
|
|
553
|
+
"\tconst openingLine =\n\t\tparams.openingLine.length === 0\n\t\t\t? \"You are a fresh visible citizen that entwurf opened in the operator's tmux session.\"\n\t\t\t: params.openingLine;\n\tvoid openingLine;"
|
|
554
|
+
],
|
|
555
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
556
|
+
"timeoutSeconds": 120,
|
|
557
|
+
"signature": "[QK:FRESHCOMP-RAIL-OWNS-PLACEMENT-SENTENCE]",
|
|
558
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
559
|
+
},
|
|
560
|
+
{
|
|
561
|
+
"claim": "FRESHCOMP-CODEX-SOCKET-LAZY",
|
|
562
|
+
"title": "the injected Codex socket is resolved for every backend — a host with no Codex home stops opening pi and claude siblings, which the inline call never did",
|
|
563
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
564
|
+
"find": ["): string[] {\n\tswitch (backend) {\n\t\tcase \"pi\":"],
|
|
565
|
+
"replace": [
|
|
566
|
+
"): string[] {\n\tconst eager = resolveCodexSocketPath();\n\tvoid eager;\n\tswitch (backend) {\n\t\tcase \"pi\":"
|
|
567
|
+
],
|
|
568
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
569
|
+
"timeoutSeconds": 120,
|
|
570
|
+
"signature": "[QK:FRESHCOMP-CODEX-SOCKET-LAZY]",
|
|
571
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
572
|
+
},
|
|
523
573
|
{
|
|
524
574
|
"claim": "FRESHCALL-CODEX-THREAD-CWD",
|
|
525
575
|
"title": "codex loses the `-C <dir>` token, so an attached thread opens in the APP-SERVER's directory while its pane sits somewhere else — the launch, the receipt and the pane all still look right",
|
|
526
|
-
"subject": "pi-extensions/lib/
|
|
527
|
-
"find": ["\t\t\t\t\"-C\",\n\t\t\t\
|
|
576
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
577
|
+
"find": ["\t\t\t\t\"-C\",\n\t\t\t\tresolveCodexLaunchCwd(),\n"],
|
|
528
578
|
"replace": [""],
|
|
529
579
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
530
580
|
"timeoutSeconds": 120,
|
|
@@ -534,8 +584,8 @@
|
|
|
534
584
|
{
|
|
535
585
|
"claim": "FRESHCALL-CWD-CALLER-ONLY",
|
|
536
586
|
"title": "the codex dialect reads THIS process's directory instead of the directory the launch chose, so a cross-repo or caller-record cwd places the pane while the thread opens somewhere else",
|
|
537
|
-
"subject": "pi-extensions/lib/
|
|
538
|
-
"find": ["\t\t\t\
|
|
587
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
588
|
+
"find": ["\t\t\t\tresolveCodexLaunchCwd(),\n"],
|
|
539
589
|
"replace": ["\t\t\t\tprocess.cwd(),\n"],
|
|
540
590
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
541
591
|
"timeoutSeconds": 120,
|
|
@@ -602,6 +652,43 @@
|
|
|
602
652
|
"timeoutSeconds": 120,
|
|
603
653
|
"signature": "[QK:FRESHCALL-CALLER-CWD-SURFACE]",
|
|
604
654
|
"signatureSource": "test/fresh-call-surfaces.contract.test.ts"
|
|
655
|
+
},
|
|
656
|
+
{
|
|
657
|
+
"claim": "FRESHCOMP-PEERS-TOOL-DIALECT",
|
|
658
|
+
"title": "the corroboration the framing offers goes back to one bare spelling, so four of the five backends are offered a tool name their own session does not expose",
|
|
659
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
660
|
+
"find": ["\tconst peersTool = FRESH_CALL_PEERS_TOOL[params.backend];"],
|
|
661
|
+
"replace": ["\tconst peersTool = \"entwurf_peers\";"],
|
|
662
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
663
|
+
"timeoutSeconds": 120,
|
|
664
|
+
"signature": "[QK:FRESHCOMP-PEERS-TOOL-DIALECT]",
|
|
665
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
666
|
+
},
|
|
667
|
+
{
|
|
668
|
+
"claim": "FRESHCOMP-RESULT-GOES-TO-CALLER",
|
|
669
|
+
"title": "the first turn stops naming where the result goes, so a sibling finishes its task, prints the answer in its own window, and the caller never learns it is done",
|
|
670
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
671
|
+
"find": [
|
|
672
|
+
"\t\t`When the task reaches its requested final result, send that result to the same target with ${tool}.`,"
|
|
673
|
+
],
|
|
674
|
+
"replace": [""],
|
|
675
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
676
|
+
"timeoutSeconds": 120,
|
|
677
|
+
"signature": "[QK:FRESHCOMP-RESULT-GOES-TO-CALLER]",
|
|
678
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
679
|
+
},
|
|
680
|
+
{
|
|
681
|
+
"claim": "FRESHCOMP-TOOL-LOAD-HINT-CLAUDE-ONLY",
|
|
682
|
+
"title": "the Claude child loses the one sentence that tells it how to load a deferred callback tool — the framing goes back to naming a tool the child cannot call on its first turn, which is the measured silence: 0/5 directly callable, 5 of 14 production launches dead",
|
|
683
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
684
|
+
"find": [
|
|
685
|
+
"\t\"claude-code\": [\n\t\t\"If ${callbackTool} is not callable yet, the entwurf-bridge server is still connecting or its\",\n\t\t'tools are deferred: load them first with ToolSearch(\"select:${callbackTool},${peersTool}\") —',\n\t\t\"it waits for the server — then call ${callbackTool}.\",\n\t],"
|
|
686
|
+
],
|
|
687
|
+
"replace": ["\t\"claude-code\": [],"],
|
|
688
|
+
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
689
|
+
"timeoutSeconds": 300,
|
|
690
|
+
"signature": "[QK:FRESHCOMP-TOOL-LOAD-HINT-CLAUDE-ONLY]",
|
|
691
|
+
"signatureSource": "test/fresh-call-composition.contract.test.ts"
|
|
605
692
|
}
|
|
606
693
|
]
|
|
607
694
|
}
|
|
@@ -118,6 +118,19 @@
|
|
|
118
118
|
"timeoutSeconds": 120,
|
|
119
119
|
"signature": "[QK:LAUNCHFENCE-WIRED-FRESH-CALL]",
|
|
120
120
|
"signatureSource": "scripts/check-mux-launcher-fence.ts"
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
"claim": "LAUNCHFENCE-EXPOSED-SMOKE-WIRED",
|
|
124
|
+
"title": "the teardown verifies a launcher snapshot taken AFTER the children ran instead of the one pinned before them — every name the fence exports is still in the file, so a presence check passes, while the oracle now compares the damage to itself and a retarget reads as 'unchanged'",
|
|
125
|
+
"subject": "scripts/smoke-herdr-fresh-call-live.ts",
|
|
126
|
+
"find": ["\t\tconst launcherProblems = verifyClaudeLauncher(launcher);"],
|
|
127
|
+
"replace": [
|
|
128
|
+
"\t\tconst launcherProblems = verifyClaudeLauncher(snapshotClaudeLauncher({ env: process.env, fixtureRoot: root }));"
|
|
129
|
+
],
|
|
130
|
+
"gate": ["bash", "run.sh", "check-mux-launcher-fence"],
|
|
131
|
+
"timeoutSeconds": 120,
|
|
132
|
+
"signature": "[QK:LAUNCHFENCE-EXPOSED-SMOKE-WIRED]",
|
|
133
|
+
"signatureSource": "scripts/check-mux-launcher-fence.ts"
|
|
121
134
|
}
|
|
122
135
|
]
|
|
123
136
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
{
|
|
6
6
|
"claim": "ADMISSION-FRESH-PARITY",
|
|
7
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/
|
|
8
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
9
9
|
"find": [
|
|
10
10
|
"export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"omp\", \"codex\"] as const;"
|
|
11
11
|
],
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
{
|
|
32
32
|
"claim": "FRESHCALL-OMP-EXPLICIT-POLICY",
|
|
33
33
|
"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",
|
|
34
|
-
"subject": "pi-extensions/lib/
|
|
34
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
35
35
|
"find": [
|
|
36
36
|
"\t\t\treturn [`--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model, \"--approval-mode\", \"yolo\"];"
|
|
37
37
|
],
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
{
|
|
45
45
|
"claim": "FRESHCALL-OMP-CALLBACK-TOOL-DIALECT",
|
|
46
46
|
"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",
|
|
47
|
-
"subject": "pi-extensions/lib/
|
|
47
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
48
48
|
"find": ["\tomp: \"mcp__entwurf_bridge_entwurf_v\","],
|
|
49
49
|
"replace": ["\tomp: \"mcp__entwurf_bridge_entwurf_v2\","],
|
|
50
50
|
"gate": ["bash", "run.sh", "check-mux-fresh-call"],
|
|
@@ -129,7 +129,7 @@
|
|
|
129
129
|
{
|
|
130
130
|
"claim": "FRESHCALL-OMP-ARGV-BOOTSTRAP-FLAG",
|
|
131
131
|
"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",
|
|
132
|
-
"subject": "pi-extensions/lib/
|
|
132
|
+
"subject": "pi-extensions/lib/fresh-call-composition.ts",
|
|
133
133
|
"find": [
|
|
134
134
|
"\t\t\treturn [`--${OMP_BOOTSTRAP_FLAG}`, composition.bootstrapPayload, \"--model\", model, \"--approval-mode\", \"yolo\"];"
|
|
135
135
|
],
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "peer-facts",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "PF-PLACEMENT-STRUCTURED",
|
|
7
|
+
"title": "stringifying placement into the human `herdr <pane>` form hands a machine consumer a presentation decision to re-parse — the pane id stops being a field and becomes a substring, which is exactly the re-implementation this verb exists to remove (#116 M2-a)",
|
|
8
|
+
"subject": "scripts/peer-facts.ts",
|
|
9
|
+
"find": ["const { payload } = renderEntwurfPeers(result);"],
|
|
10
|
+
"replace": [
|
|
11
|
+
"const { payload } = renderEntwurfPeers(result);\npayload.peers = payload.peers.map((p) => ({\n\t...p,\n\tplacement: (p.placement.kind === \"herdr-pane\" ? `herdr ${p.placement.paneId}` : p.placement.kind) as never,\n}));"
|
|
12
|
+
],
|
|
13
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
14
|
+
"timeoutSeconds": 120,
|
|
15
|
+
"signature": "[QK:PF-PLACEMENT-STRUCTURED]",
|
|
16
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"claim": "PF-PEER-KEYSET-EXACT",
|
|
20
|
+
"title": "letting a herdr display verdict (agent_status) into a peer row opens the one door through which herdr's screen judgement becomes an entwurf fact, and from there a rename away from delivery liveness (#116 M2-a, docs/herdr-launch-rail.md §9)",
|
|
21
|
+
"subject": "scripts/peer-facts.ts",
|
|
22
|
+
"find": ["const projection = { schemaVersion: 1, storeDir, ...payload };"],
|
|
23
|
+
"replace": [
|
|
24
|
+
"const projection = {\n\tschemaVersion: 1,\n\tstoreDir,\n\t...payload,\n\tpeers: payload.peers.map((p) => ({ ...p, agentStatus: \"idle\" })),\n};"
|
|
25
|
+
],
|
|
26
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
27
|
+
"timeoutSeconds": 120,
|
|
28
|
+
"signature": "[QK:PF-PEER-KEYSET-EXACT]",
|
|
29
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"claim": "PF-NO-SOCKET-COORDINATE",
|
|
33
|
+
"title": "republishing the control-socket dir undoes the #50 C4 retirement that removed the legacy listing together with the controlDir it exposed — the record is the sole address axis and a socket path is dispatch-internal transport, so a convenience field here reopens a second address-shaped axis (#116 M2-a)",
|
|
34
|
+
"subject": "scripts/peer-facts.ts",
|
|
35
|
+
"find": ["const projection = { schemaVersion: 1, storeDir, ...payload };"],
|
|
36
|
+
"replace": ["const projection = { schemaVersion: 1, storeDir, controlDir, ...payload };"],
|
|
37
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
38
|
+
"timeoutSeconds": 120,
|
|
39
|
+
"signature": "[QK:PF-NO-SOCKET-COORDINATE]",
|
|
40
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"claim": "PF-DIAGNOSTICS-PRESERVED",
|
|
44
|
+
"title": "dropping the provider's diagnostics turns a store carrying hazards into a clean-looking listing at exit 0 — the consumer is told about the healthy citizens and never about what was refused (#116 M2-a)",
|
|
45
|
+
"subject": "scripts/peer-facts.ts",
|
|
46
|
+
"find": ["process.stdout.write(`${JSON.stringify(projection, null, 2)}\\n`);"],
|
|
47
|
+
"replace": ["process.stdout.write(`${JSON.stringify({ ...projection, diagnostics: [] }, null, 2)}\\n`);"],
|
|
48
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
49
|
+
"timeoutSeconds": 120,
|
|
50
|
+
"signature": "[QK:PF-DIAGNOSTICS-PRESERVED]",
|
|
51
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"claim": "PF-CONTROL-DIR-PROBED",
|
|
55
|
+
"title": "ignoring ENTWURF_DIR probes a different socket world than the bridge does, so this verb and entwurf_peers can answer the same question from two worlds while both look green (#116 M2-a)",
|
|
56
|
+
"subject": "scripts/peer-facts.ts",
|
|
57
|
+
"find": ["\tsocket: { dir: controlDir },"],
|
|
58
|
+
"replace": ["\tsocket: { dir: defaultControlSocketDir(os.homedir()) },"],
|
|
59
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
60
|
+
"timeoutSeconds": 120,
|
|
61
|
+
"signature": "[QK:PF-CONTROL-DIR-PROBED]",
|
|
62
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
"claim": "PF-NO-OBSERVATION-BUDGET",
|
|
66
|
+
"title": "rationing observations emits `unobserved` for rows nobody chose to skip, and in a machine payload that is indistinguishable from `nobody could look` — a fabricated measurement about a read that did not happen (#116 M2-a)",
|
|
67
|
+
"subject": "scripts/peer-facts.ts",
|
|
68
|
+
"find": ["\tsocket: { dir: controlDir },\n\t// No `observationLimit`"],
|
|
69
|
+
"replace": ["\tsocket: { dir: controlDir },\n\tobservationLimit: 0,\n\t// No `observationLimit`"],
|
|
70
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
71
|
+
"timeoutSeconds": 120,
|
|
72
|
+
"signature": "[QK:PF-NO-OBSERVATION-BUDGET]",
|
|
73
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"claim": "PF-EXIT-UNREADABLE",
|
|
77
|
+
"title": "answering an unreadable store with exit 0 makes an unreadable host look like an empty one — the same false-success class the #65 exit contract exists to refuse, one axis out (#116 M2-a)",
|
|
78
|
+
"subject": "scripts/peer-facts.ts",
|
|
79
|
+
"find": ["\tprocess.exit(3); // see the EXIT CONTRACT above: 3 = unreadable store, never an empty one"],
|
|
80
|
+
"replace": ["\tprocess.exit(0); // see the EXIT CONTRACT above: 3 = unreadable store, never an empty one"],
|
|
81
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
82
|
+
"timeoutSeconds": 120,
|
|
83
|
+
"signature": "[QK:PF-EXIT-UNREADABLE]",
|
|
84
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"claim": "PF-USAGE",
|
|
88
|
+
"title": "reading a dash argv as a store directory answers `--help` with `empty store, exit 0` — a silent wrong fact where a refusal belongs (#116 M2-a)",
|
|
89
|
+
"subject": "scripts/peer-facts.ts",
|
|
90
|
+
"find": ["if (process.argv.length > 3 || (arg !== undefined && arg.startsWith(\"-\"))) {"],
|
|
91
|
+
"replace": ["if (process.argv.length > 3) {"],
|
|
92
|
+
"gate": ["bash", "run.sh", "check-peer-facts"],
|
|
93
|
+
"timeoutSeconds": 120,
|
|
94
|
+
"signature": "[QK:PF-USAGE]",
|
|
95
|
+
"signatureSource": "scripts/check-peer-facts.ts"
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "pi-launch",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "PILAUNCH-FLAG-SSOT",
|
|
7
|
+
"title": "the launcher spells the control flag itself, so a typo in run.sh silently produces a pi that is not a citizen and reports nothing",
|
|
8
|
+
"subject": "run.sh",
|
|
9
|
+
"find": [" exec \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
10
|
+
"replace": [" exec \"$entwurf_pi_bin\" --entwurf-controll \"$@\""],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
12
|
+
"timeoutSeconds": 300,
|
|
13
|
+
"signature": "[QK:PILAUNCH-FLAG-SSOT]",
|
|
14
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"claim": "PILAUNCH-VERB-DROPPED",
|
|
18
|
+
"title": "without the shift the dispatcher verb stays in the forwarded argv and `pi` arrives at the vendor as a prompt argument",
|
|
19
|
+
"subject": "run.sh",
|
|
20
|
+
"find": [" shift || true\n if [ -n \"${ENTWURF_PI_LAUNCH_ACTIVE:-}\" ]; then"],
|
|
21
|
+
"replace": [" if [ -n \"${ENTWURF_PI_LAUNCH_ACTIVE:-}\" ]; then"],
|
|
22
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
23
|
+
"timeoutSeconds": 300,
|
|
24
|
+
"signature": "[QK:PILAUNCH-VERB-DROPPED]",
|
|
25
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"claim": "PILAUNCH-FLAG-FIRST",
|
|
29
|
+
"title": "injecting the flag AFTER the operator argv puts it behind a positional prompt, where pi reads it as data instead of standing up a control socket",
|
|
30
|
+
"subject": "run.sh",
|
|
31
|
+
"find": [" exec \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
32
|
+
"replace": [" exec \"$entwurf_pi_bin\" \"$@\" --entwurf-control"],
|
|
33
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
34
|
+
"timeoutSeconds": 300,
|
|
35
|
+
"signature": "[QK:PILAUNCH-FLAG-FIRST]",
|
|
36
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
"claim": "PILAUNCH-NOTHING-ELSE-INJECTED",
|
|
40
|
+
"title": "a launcher that also injects operator taste stops being a spelling and starts deciding the session (Rule 9)",
|
|
41
|
+
"subject": "run.sh",
|
|
42
|
+
"find": [" exec \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
43
|
+
"replace": [" exec \"$entwurf_pi_bin\" --entwurf-control --emacs-agent-socket \"$@\""],
|
|
44
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
45
|
+
"timeoutSeconds": 300,
|
|
46
|
+
"signature": "[QK:PILAUNCH-NOTHING-ELSE-INJECTED]",
|
|
47
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
"claim": "PILAUNCH-ARGV-BYTES",
|
|
51
|
+
"title": "an unquoted forward word-splits the operator argv and drops empty elements, so a quoted prompt silently becomes several arguments",
|
|
52
|
+
"subject": "run.sh",
|
|
53
|
+
"find": [" exec \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
54
|
+
"replace": [" exec \"$entwurf_pi_bin\" --entwurf-control $@"],
|
|
55
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
56
|
+
"timeoutSeconds": 300,
|
|
57
|
+
"signature": "[QK:PILAUNCH-ARGV-BYTES]",
|
|
58
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"claim": "PILAUNCH-EXEC-KEEPS-PID",
|
|
62
|
+
"title": "forking instead of exec leaves run.sh as a parent that supervises nothing and owns neither the terminal nor the exit",
|
|
63
|
+
"subject": "run.sh",
|
|
64
|
+
"find": [" exec \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
65
|
+
"replace": [" \"$entwurf_pi_bin\" --entwurf-control \"$@\""],
|
|
66
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
67
|
+
"timeoutSeconds": 300,
|
|
68
|
+
"signature": "[QK:PILAUNCH-EXEC-KEEPS-PID]",
|
|
69
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"claim": "PILAUNCH-VENDOR-ABSENT",
|
|
73
|
+
"title": "an absent vendor that exits 0 is the false success this repo refuses: nothing launched and the caller was told it worked",
|
|
74
|
+
"subject": "run.sh",
|
|
75
|
+
"find": [
|
|
76
|
+
" echo \" 'entwurf pi' launches the pi coding agent; it does not install one.\" >&2\n exit 1"
|
|
77
|
+
],
|
|
78
|
+
"replace": [
|
|
79
|
+
" echo \" 'entwurf pi' launches the pi coding agent; it does not install one.\" >&2\n exit 0"
|
|
80
|
+
],
|
|
81
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
82
|
+
"timeoutSeconds": 300,
|
|
83
|
+
"signature": "[QK:PILAUNCH-VENDOR-ABSENT]",
|
|
84
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"claim": "PILAUNCH-SENTINEL-EXPORTED",
|
|
88
|
+
"title": "a sentinel that is set but not exported is invisible to the re-entered child, so the recursion fence never fires and the terminal hangs",
|
|
89
|
+
"subject": "run.sh",
|
|
90
|
+
"find": [" export ENTWURF_PI_LAUNCH_ACTIVE=1"],
|
|
91
|
+
"replace": [" ENTWURF_PI_LAUNCH_ACTIVE=1"],
|
|
92
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
93
|
+
"timeoutSeconds": 300,
|
|
94
|
+
"signature": "[QK:PILAUNCH-SENTINEL-EXPORTED]",
|
|
95
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
"claim": "PILAUNCH-RECURSION-FENCE",
|
|
99
|
+
"title": "with the fence removed a PATH `pi` that shells back here spins forever, and the symptom is a hung terminal rather than an error",
|
|
100
|
+
"subject": "run.sh",
|
|
101
|
+
"find": [
|
|
102
|
+
" if [ -n \"${ENTWURF_PI_LAUNCH_ACTIVE:-}\" ]; then\n echo \"entwurf: recursive managed launch detected (ENTWURF_PI_LAUNCH_ACTIVE is already set).\" >&2"
|
|
103
|
+
],
|
|
104
|
+
"replace": [
|
|
105
|
+
" if false; then\n echo \"entwurf: recursive managed launch detected (ENTWURF_PI_LAUNCH_ACTIVE is already set).\" >&2"
|
|
106
|
+
],
|
|
107
|
+
"gate": ["bash", "run.sh", "check-pi-launch"],
|
|
108
|
+
"timeoutSeconds": 300,
|
|
109
|
+
"signature": "[QK:PILAUNCH-RECURSION-FENCE]",
|
|
110
|
+
"signatureSource": "scripts/check-pi-launch.ts"
|
|
111
|
+
}
|
|
112
|
+
]
|
|
113
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
12
12
|
"timeoutSeconds": 60,
|
|
13
13
|
"signature": "[QK:RESUMEARGS-NO-HEADLESS]",
|
|
14
|
-
"signatureSource": "
|
|
14
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
15
15
|
},
|
|
16
16
|
{
|
|
17
17
|
"claim": "RESUMEARGS-CONTROL-FIRST",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
25
25
|
"timeoutSeconds": 60,
|
|
26
26
|
"signature": "[QK:RESUMEARGS-CONTROL-FIRST]",
|
|
27
|
-
"signatureSource": "
|
|
27
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"claim": "RESUMEARGS-EXT-ONCE-BEFORE-SESSION",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
38
38
|
"timeoutSeconds": 60,
|
|
39
39
|
"signature": "[QK:RESUMEARGS-EXT-ONCE-BEFORE-SESSION]",
|
|
40
|
-
"signatureSource": "
|
|
40
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"claim": "RESUMEARGS-SESSION-IS-FILE",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
49
49
|
"timeoutSeconds": 60,
|
|
50
50
|
"signature": "[QK:RESUMEARGS-SESSION-IS-FILE]",
|
|
51
|
-
"signatureSource": "
|
|
51
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
52
52
|
},
|
|
53
53
|
{
|
|
54
54
|
"claim": "RESUMEARGS-PROVIDER-OPTIONAL",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
60
60
|
"timeoutSeconds": 60,
|
|
61
61
|
"signature": "[QK:RESUMEARGS-PROVIDER-OPTIONAL]",
|
|
62
|
-
"signatureSource": "
|
|
62
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
"claim": "RESUMEARGS-NO-PROMPT-TAIL",
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"gate": ["bash", "run.sh", "check-entwurf-resume-args"],
|
|
71
71
|
"timeoutSeconds": 60,
|
|
72
72
|
"signature": "[QK:RESUMEARGS-NO-PROMPT-TAIL]",
|
|
73
|
-
"signatureSource": "
|
|
73
|
+
"signatureSource": "pi-extensions/lib/entwurf-resume-args.test.ts"
|
|
74
74
|
}
|
|
75
75
|
]
|
|
76
76
|
}
|
|
@@ -88,6 +88,39 @@
|
|
|
88
88
|
"timeoutSeconds": 60,
|
|
89
89
|
"signature": "[QK:SELFADDR-MAILBOX-WAKE-SEAM]",
|
|
90
90
|
"signatureSource": "scripts/check-entwurf-self-address.ts"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"claim": "SELFADDR-UNCITIZENED-NOTICED",
|
|
94
|
+
"title": "passing a constant instead of the real flag makes the decision unreachable and the notice a property of nothing — this is the defect an independent review walked through the first cut's source regex with (measured 2026-09-17: moving the call into the citizen branch left the gate 51/51 green), because a regex sees that a call exists and cannot see which fact it carries",
|
|
95
|
+
"subject": "pi-extensions/entwurf-control.ts",
|
|
96
|
+
"find": ["\t\tawait noticeUncitizenedSession(ctx, enabled);"],
|
|
97
|
+
"replace": ["\t\tawait noticeUncitizenedSession(ctx, false);"],
|
|
98
|
+
"gate": ["bash", "run.sh", "check-entwurf-self-address"],
|
|
99
|
+
"timeoutSeconds": 300,
|
|
100
|
+
"signature": "[QK:SELFADDR-UNCITIZENED-NOTICED]",
|
|
101
|
+
"signatureSource": "scripts/check-entwurf-self-address.ts"
|
|
102
|
+
},
|
|
103
|
+
{
|
|
104
|
+
"claim": "SELFADDR-UNCITIZENED-ONCE",
|
|
105
|
+
"title": "dropping the line that records the notice fired turns a one-time hint into a nag: `refreshServer` runs again on every session switch, so the operator who already read the sentence reads it again each time — and the second cut's own comment is what claims this cannot happen",
|
|
106
|
+
"subject": "pi-extensions/entwurf-control.ts",
|
|
107
|
+
"find": ["\tuncitizenedNoticeShown = true;"],
|
|
108
|
+
"replace": ["\tvoid uncitizenedNoticeShown;"],
|
|
109
|
+
"gate": ["bash", "run.sh", "check-entwurf-self-address"],
|
|
110
|
+
"timeoutSeconds": 300,
|
|
111
|
+
"signature": "[QK:SELFADDR-UNCITIZENED-ONCE]",
|
|
112
|
+
"signatureSource": "scripts/check-entwurf-self-address.ts"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"claim": "SELFADDR-UNCITIZENED-DECISION",
|
|
116
|
+
"title": "letting the decision answer yes for a session that DOES have --entwurf-control tells a citizen it is not one — the exact inversion the mirror contract exists to prevent, and the reason the three conditions are a truth table here instead of ifs at a call site a regex was pretending to cover",
|
|
117
|
+
"subject": "pi-extensions/lib/entwurf-self-address.ts",
|
|
118
|
+
"find": ["\tif (facts.controlEnabled) return false;"],
|
|
119
|
+
"replace": ["\tif (false && facts.controlEnabled) return false;"],
|
|
120
|
+
"gate": ["bash", "run.sh", "check-entwurf-self-address"],
|
|
121
|
+
"timeoutSeconds": 300,
|
|
122
|
+
"signature": "[QK:SELFADDR-UNCITIZENED-DECISION]",
|
|
123
|
+
"signatureSource": "scripts/check-entwurf-self-address.ts"
|
|
91
124
|
}
|
|
92
125
|
]
|
|
93
126
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"lane": "typing-call-fence",
|
|
4
|
+
"mutants": [
|
|
5
|
+
{
|
|
6
|
+
"claim": "TYPEFENCE-PRODUCTION-CLEAN",
|
|
7
|
+
"title": "a production module acquires a typing call — the launch rail starts reaching a sibling through the place a human types, which is the one channel this product measured and refused at design time and the one kind of 'delivery' that is only a screen write (Hard Rule 16)",
|
|
8
|
+
"subject": "pi-extensions/lib/herdr-fresh-call.ts",
|
|
9
|
+
"find": ["\t\t\"tab\",\n\t\t\"create\","],
|
|
10
|
+
"replace": ["\t\t\"tab\",\n\t\t\"create\",\n\t\t\"send-keys\","],
|
|
11
|
+
"gate": ["bash", "run.sh", "check-typing-call-fence"],
|
|
12
|
+
"timeoutSeconds": 120,
|
|
13
|
+
"signature": "[QK:TYPEFENCE-PRODUCTION-CLEAN]",
|
|
14
|
+
"signatureSource": "scripts/check-typing-call-fence.ts"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|