@junghanacs/entwurf 0.30.0 → 0.31.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.
Files changed (69) hide show
  1. package/AGENTS.md +1 -0
  2. package/CHANGELOG.md +229 -0
  3. package/DELIVERY.md +1 -0
  4. package/README.md +49 -4
  5. package/VERIFY.md +23 -4
  6. package/demo/README.md +1 -1
  7. package/docs/acp-backend-rail.md +111 -18
  8. package/docs/setup-clean-host.md +104 -4
  9. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +7 -7
  10. package/mcp/entwurf-bridge/dist/pi-extensions/entwurf-capabilities.json +1 -0
  11. package/mcp/entwurf-bridge/dist/pi-extensions/lib/acp/backend-adapter.js +43 -0
  12. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-deliverability.js +7 -1
  13. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +34 -3
  14. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-sender-identity.js +7 -1
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +28 -2
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +30 -2
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-fresh-preflight.js +92 -0
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-durable-runtime.js +288 -0
  19. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +744 -0
  20. package/mcp/entwurf-bridge/src/index.ts +7 -7
  21. package/mcp/entwurf-bridge/tsconfig.build.json +8 -1
  22. package/package.json +15 -12
  23. package/pi/entwurf-capabilities.json +1 -0
  24. package/pi/pi-durable/bootstrap.mjs +281 -0
  25. package/pi/pi-durable/overlay/runtime-contacts.patch +91 -0
  26. package/pi/pi-durable/overlay/upstream-pin.json +16 -0
  27. package/pi-extensions/lib/acp/backend-adapter.ts +68 -0
  28. package/pi-extensions/lib/acp/backend.ts +41 -5
  29. package/pi-extensions/lib/entwurf-deliverability.ts +7 -1
  30. package/pi-extensions/lib/fresh-call-composition.ts +42 -7
  31. package/pi-extensions/lib/meta-sender-identity.ts +7 -1
  32. package/pi-extensions/lib/meta-session.ts +28 -2
  33. package/pi-extensions/lib/mux-fresh-call.ts +34 -2
  34. package/pi-extensions/lib/pi-durable-fresh-preflight.ts +113 -0
  35. package/pi-extensions/lib/pi-durable-runtime.ts +384 -0
  36. package/pi-extensions/meta-bridge-pi-durable.ts +1020 -0
  37. package/run.sh +214 -36
  38. package/scripts/check-fresh-call-dispatch.ts +18 -0
  39. package/scripts/check-gate-qualification.ts +4 -2
  40. package/scripts/check-herdr-plugin-build.ts +159 -57
  41. package/scripts/check-pi-durable-contact.ts +834 -0
  42. package/scripts/check-pi-durable-receive.ts +1116 -0
  43. package/scripts/check-pi-durable-send.ts +1661 -0
  44. package/scripts/fixtures/herdr-supply.json +8 -8
  45. package/scripts/lib/pi-durable-fresh-live-receipts.ts +139 -0
  46. package/scripts/lib/pi-durable-r1.ts +100 -0
  47. package/scripts/lib/pi-durable-reap.ts +27 -0
  48. package/scripts/lib/pi-durable-receive.ts +137 -0
  49. package/scripts/mutants/acp-prompt-lifecycle.json +2 -2
  50. package/scripts/mutants/acp-vendor-rejection.json +62 -0
  51. package/scripts/mutants/control-send-receipt.json +1 -1
  52. package/scripts/mutants/copilot-birth.json +2 -2
  53. package/scripts/mutants/herdr-plugin-build.json +11 -0
  54. package/scripts/mutants/herdr-supply.json +3 -3
  55. package/scripts/mutants/meta-hook-session-switch.json +4 -2
  56. package/scripts/mutants/mux-fresh-call.json +69 -3
  57. package/scripts/mutants/omp-birth.json +2 -2
  58. package/scripts/mutants/omp-fresh.json +6 -4
  59. package/scripts/mutants/pack-install.json +3 -3
  60. package/scripts/mutants/pi-durable.json +390 -0
  61. package/scripts/mutants/pi-floor.json +2 -2
  62. package/scripts/pi-durable-contact-host.mjs +105 -0
  63. package/scripts/pi-durable-receive-host.mjs +127 -0
  64. package/scripts/pi-durable-send-host.mjs +213 -0
  65. package/scripts/smoke-acp-raw-turn-live.ts +1 -1
  66. package/scripts/smoke-herdr-fresh-call-live.ts +21 -7
  67. package/scripts/smoke-pi-durable-fresh-live.ts +624 -0
  68. package/scripts/smoke-setup-verdict.sh +21 -2
  69. package/scripts/tsconfig.json +1 -0
@@ -151,7 +151,7 @@
151
151
  "title": "MCP drops the required model field from fresh-call while the composition still expects one",
152
152
  "subject": "mcp/entwurf-bridge/src/index.ts",
153
153
  "find": [
154
- "\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi, a Claude Code model id/alias, or a Copilot/OMP/Codex model name.\",\n\t\t\t),\n"
154
+ "\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi, provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name.\",\n\t\t\t),\n"
155
155
  ],
156
156
  "replace": [""],
157
157
  "gate": ["bash", "run.sh", "check-mux-fresh-call"],
@@ -192,6 +192,17 @@
192
192
  "signature": "[QK:PIIMPORT-WORK-SURFACE]",
193
193
  "signatureSource": "run.sh"
194
194
  },
195
+ {
196
+ "claim": "PIIMPORT-DURABLE-BOOTSTRAP-EXACT",
197
+ "title": "the #129 durable exception loses its file scope: the two experimental durable specifiers become allowed in every file, so a new pi private-subpath import elsewhere passes the floor",
198
+ "subject": "run.sh",
199
+ "find": [" | sed -E \"/^pi\\/pi-durable\\/bootstrap\\.mjs:[0-9]+:/ s#"],
200
+ "replace": [" | sed -E \"s#"],
201
+ "gate": ["bash", "run.sh", "check-pi-import-surface"],
202
+ "timeoutSeconds": 60,
203
+ "signature": "[QK:PIIMPORT-DURABLE-BOOTSTRAP-EXACT]",
204
+ "signatureSource": "run.sh"
205
+ },
195
206
  {
196
207
  "claim": "VITEST-FAILED-TITLE-ATTRIBUTION",
197
208
  "title": "the pilot's kill attribution collects PASSING test titles instead of failed ones, recreating the code-frame false-KILLED hole this lane exists to close",
@@ -323,8 +334,8 @@
323
334
  "claim": "FRESHCALL-BACKEND-SET-SURFACE-PARITY",
324
335
  "title": "a backend the composition can open is missing from the MCP surface enum — the capability exists and no external host can reach it",
325
336
  "subject": "mcp/entwurf-bridge/src/index.ts",
326
- "find": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\", \"omp\", \"codex\"])"],
327
- "replace": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\", \"omp\"])"],
337
+ "find": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\", \"omp\", \"codex\", \"pi-durable\"])"],
338
+ "replace": ["\t\t\t.enum([\"pi\", \"claude-code\", \"copilot\", \"omp\", \"pi-durable\"])"],
328
339
  "gate": ["bash", "run.sh", "check-mux-fresh-call"],
329
340
  "timeoutSeconds": 180,
330
341
  "signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY]",
@@ -700,6 +711,61 @@
700
711
  "timeoutSeconds": 120,
701
712
  "signature": "[QK:FRESHCALL-CALLBACK-ENV]",
702
713
  "signatureSource": "test/mux-fresh-call.test.ts"
714
+ },
715
+ {
716
+ "claim": "FRESHCALL-PI-DURABLE-ARGV",
717
+ "title": "pi-durable loses its explicit task-wide width, so the packaged bootstrap refuses a launch the composition said it built",
718
+ "subject": "pi-extensions/lib/fresh-call-composition.ts",
719
+ "find": ["\t\t\t\t\"--width\",\n\t\t\t\t\"task-wide\",\n"],
720
+ "replace": [""],
721
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
722
+ "timeoutSeconds": 120,
723
+ "signature": "[QK:FRESHCALL-PI-DURABLE-ARGV]",
724
+ "signatureSource": "test/mux-fresh-call.test.ts"
725
+ },
726
+ {
727
+ "claim": "FRESHCALL-PI-DURABLE-PREFLIGHT-PREMUTATION",
728
+ "title": "the pi-durable runtime/unit preflight is skipped, so an absent or drifted operator runtime is discovered only after a window was placed",
729
+ "subject": "pi-extensions/lib/mux-fresh-call.ts",
730
+ "find": ["\tif (params.backend === \"pi-durable\") {\n"],
731
+ "replace": ["\tif (false) {\n"],
732
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
733
+ "timeoutSeconds": 120,
734
+ "signature": "[QK:FRESHCALL-PI-DURABLE-PREFLIGHT-PREMUTATION]",
735
+ "signatureSource": "test/mux-fresh-call.test.ts"
736
+ },
737
+ {
738
+ "claim": "FRESHCALL-PI-DURABLE-MANAGED-RUNTIME",
739
+ "title": "pi-durable opens the bare app instead of the managed `entwurf pi-durable`, so nothing verifies the operator runtime against the pin before its resolver runs",
740
+ "subject": "pi-extensions/lib/mux-fresh-call.ts",
741
+ "find": ["\t\"pi-durable\": \"entwurf\","],
742
+ "replace": ["\t\"pi-durable\": \"pi\","],
743
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
744
+ "timeoutSeconds": 120,
745
+ "signature": "[QK:FRESHCALL-PI-DURABLE-MANAGED-RUNTIME]",
746
+ "signatureSource": "test/mux-fresh-call.test.ts"
747
+ },
748
+ {
749
+ "claim": "FRESHCALL-PI-DURABLE-CALLBACK-DIALECT",
750
+ "title": "pi-durable is told the composed MCP callback name, which the durable contact never registers — the contact offers the bridge verbs under their bare names",
751
+ "subject": "pi-extensions/lib/fresh-call-composition.ts",
752
+ "find": ["\t\"pi-durable\": \"entwurf_callback\","],
753
+ "replace": ["\t\"pi-durable\": \"mcp__entwurf-bridge__entwurf_callback\","],
754
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
755
+ "timeoutSeconds": 120,
756
+ "signature": "[QK:FRESHCALL-PI-DURABLE-CALLBACK-DIALECT]",
757
+ "signatureSource": "test/mux-fresh-call.test.ts"
758
+ },
759
+ {
760
+ "claim": "PD-FRESH-LIVE-FOREIGN-SENDER-REFUSED",
761
+ "title": "the pi-durable LIVE gate's Pi-side oracle drops its expected-sender check, so the exact payload relayed by any other citizen counts as pd's delivery",
762
+ "subject": "scripts/lib/pi-durable-fresh-live-receipts.ts",
763
+ "find": ["\t\tif (senders.length === 1 && senders[0] === expectedSender) hits.push({ row, index });"],
764
+ "replace": ["\t\tif (senders.length === 1) hits.push({ row, index });"],
765
+ "gate": ["bash", "run.sh", "check-mux-fresh-call"],
766
+ "timeoutSeconds": 120,
767
+ "signature": "[QK:PD-FRESH-LIVE-FOREIGN-SENDER-REFUSED]",
768
+ "signatureSource": "test/pi-durable-fresh-live-receipts.test.ts"
703
769
  }
704
770
  ]
705
771
  }
@@ -66,10 +66,10 @@
66
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
67
  "subject": "pi-extensions/lib/meta-sender-identity.ts",
68
68
  "find": [
69
- "export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\", \"omp\"];"
69
+ "export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\n\t\"claude-code\",\n\t\"antigravity\",\n\t\"copilot\",\n\t\"omp\",\n\t\"pi-durable\",\n];"
70
70
  ],
71
71
  "replace": [
72
- "export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\"claude-code\", \"antigravity\", \"copilot\"];"
72
+ "export const META_SENDER_BACKENDS: readonly MetaBackend[] = [\n\t\"claude-code\",\n\t\"antigravity\",\n\t\"copilot\",\n\t\"pi-durable\",\n];"
73
73
  ],
74
74
  "gate": ["bash", "run.sh", "check-omp-birth-hook"],
75
75
  "timeoutSeconds": 300,
@@ -7,9 +7,11 @@
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
8
  "subject": "pi-extensions/lib/fresh-call-composition.ts",
9
9
  "find": [
10
- "export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"omp\", \"codex\"] as const;"
10
+ "export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"omp\", \"codex\", \"pi-durable\"] as const;"
11
+ ],
12
+ "replace": [
13
+ "export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"codex\", \"pi-durable\"] as const;"
11
14
  ],
12
- "replace": ["export const FRESH_CALL_BACKENDS = [\"pi\", \"claude-code\", \"copilot\", \"codex\"] as const;"],
13
15
  "gate": ["bash", "run.sh", "check-harness-admission-parity"],
14
16
  "timeoutSeconds": 300,
15
17
  "signature": "[QK:ADMISSION-FRESH-PARITY]",
@@ -119,8 +121,8 @@
119
121
  "claim": "FRESHCALL-BACKEND-SET-SURFACE-PARITY-SKILL",
120
122
  "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",
121
123
  "subject": ".claude/skills/entwurf-dev/SKILL.md",
122
- "find": ["backend는 정확히 `pi | claude-code | copilot | omp | codex`이고"],
123
- "replace": ["backend는 정확히 `pi | claude-code | copilot | omp`이고"],
124
+ "find": ["backend는 정확히 `pi | claude-code | copilot | omp | codex | pi-durable`이고"],
125
+ "replace": ["backend는 정확히 `pi | claude-code | copilot | omp | pi-durable`이고"],
124
126
  "gate": ["bash", "run.sh", "check-mux-fresh-call"],
125
127
  "timeoutSeconds": 300,
126
128
  "signature": "[QK:FRESHCALL-BACKEND-SET-SURFACE-PARITY-SKILL]",
@@ -6,7 +6,7 @@
6
6
  "claim": "PACK-INSTALL-PIN-MATCHER-BOUNDED",
7
7
  "title": "the pin-leak matcher loses its version boundary and blesses substring lookalikes — @0.85.10 reads as the pinned 0.85.1 and the gate announces a verified tree it never verified (independent review, 2026-08-25)",
8
8
  "subject": "run.sh",
9
- "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
9
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.2(_|$)' || true"],
10
10
  "replace": [" grep '^@earendil-works+' | grep -v '@0\\.87\\.1' || true"],
11
11
  "gate": ["bash", "run.sh", "check-pack-pin-matcher"],
12
12
  "timeoutSeconds": 120,
@@ -17,8 +17,8 @@
17
17
  "claim": "PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE",
18
18
  "title": "the pin-leak matcher narrows back to the pi-* families and goes blind to a non-pi member of the same runtime closure — @earendil-works/chord (new in pi 0.85.0, a runtime dependency of pi-coding-agent/pi-agent-core/pi-client/pi-protocol) floats unpinned while the gate prints a verified pin (measured 2026-09-06 on a real 0.85.1 install tree)",
19
19
  "subject": "run.sh",
20
- "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
21
- "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@1\\.0\\.0(_|$)' || true"],
20
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.0\\.2(_|$)' || true"],
21
+ "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@1\\.0\\.2(_|$)' || true"],
22
22
  "gate": ["bash", "run.sh", "check-pack-pin-matcher"],
23
23
  "timeoutSeconds": 120,
24
24
  "signature": "[QK:PACK-INSTALL-PIN-MATCHER-COVERS-CLOSURE]",
@@ -0,0 +1,390 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "pi-durable",
4
+ "mutants": [
5
+ {
6
+ "claim": "PI-DURABLE-RUNTIME-UNTRACKED-DRIFT",
7
+ "title": "a non-ignored untracked file in the operator runtime no longer counts as pin drift",
8
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
9
+ "find": [" || facts.untracked !== \"\" || "],
10
+ "replace": [" || "],
11
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
12
+ "timeoutSeconds": 300,
13
+ "signature": "[QK:PI-DURABLE-RUNTIME-UNTRACKED-DRIFT]",
14
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
15
+ "build": {
16
+ "argv": ["bash", "scripts/build-bridge.sh"],
17
+ "output": "mcp/entwurf-bridge/dist"
18
+ }
19
+ },
20
+ {
21
+ "claim": "PI-DURABLE-RUNTIME-MODELDATA-DRIFT",
22
+ "title": "model data that is not the pinned bytes is no longer its own refusal",
23
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
24
+ "find": ["\t\treturn \"pi-durable-runtime-modeldata-drift\";\n"],
25
+ "replace": ["\t\treturn null;\n"],
26
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
27
+ "timeoutSeconds": 300,
28
+ "signature": "[QK:PI-DURABLE-RUNTIME-MODELDATA-DRIFT]",
29
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
30
+ "build": {
31
+ "argv": ["bash", "scripts/build-bridge.sh"],
32
+ "output": "mcp/entwurf-bridge/dist"
33
+ }
34
+ },
35
+ {
36
+ "claim": "PI-DURABLE-RUNTIME-READ-ONLY",
37
+ "title": "verification runs git against the operator checkout's own index instead of a private copy, so a stale stat cache is rewritten",
38
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
39
+ "find": ["const onCopy = { ...base, GIT_INDEX_FILE: copy };"],
40
+ "replace": ["const onCopy = { ...base };"],
41
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
42
+ "timeoutSeconds": 300,
43
+ "signature": "[QK:PI-DURABLE-RUNTIME-READ-ONLY]",
44
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
45
+ "build": {
46
+ "argv": ["bash", "scripts/build-bridge.sh"],
47
+ "output": "mcp/entwurf-bridge/dist"
48
+ }
49
+ },
50
+ {
51
+ "claim": "PI-DURABLE-RUNTIME-LOCATOR-FIXED",
52
+ "title": "a relative XDG_DATA_HOME is honoured, so the runtime's one fixed place follows the caller's cwd",
53
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
54
+ "find": [" && xdg.length > 0 && path.isAbsolute(xdg)) {"],
55
+ "replace": [" && xdg.length > 0) {"],
56
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
57
+ "timeoutSeconds": 300,
58
+ "signature": "[QK:PI-DURABLE-RUNTIME-LOCATOR-FIXED]",
59
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
60
+ "build": {
61
+ "argv": ["bash", "scripts/build-bridge.sh"],
62
+ "output": "mcp/entwurf-bridge/dist"
63
+ }
64
+ },
65
+ {
66
+ "claim": "PI-DURABLE-RUNTIME-STAGED-DRIFT",
67
+ "title": "the index == HEAD term leaves the verdict, so a staged change behind an equal worktree diff verifies as the pin",
68
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
69
+ "find": ["\tif (!facts.indexMatchesHead) return \"pi-durable-runtime-pin-drift\";\n"],
70
+ "replace": [""],
71
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
72
+ "timeoutSeconds": 300,
73
+ "signature": "[QK:PI-DURABLE-RUNTIME-STAGED-DRIFT]",
74
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
75
+ "build": {
76
+ "argv": ["bash", "scripts/build-bridge.sh"],
77
+ "output": "mcp/entwurf-bridge/dist"
78
+ }
79
+ },
80
+ {
81
+ "claim": "PI-DURABLE-ENTRY-GUARD-FLOOR-SAFE",
82
+ "title": "the verifier's entry guard goes back to import.meta.main, which the floor's runner can misread as the process entry",
83
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
84
+ "find": ["if (invokedDirectly) {\n"],
85
+ "replace": ["if (import.meta.main) {\n"],
86
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
87
+ "timeoutSeconds": 300,
88
+ "signature": "[QK:PI-DURABLE-ENTRY-GUARD-FLOOR-SAFE]",
89
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
90
+ "build": {
91
+ "argv": ["bash", "scripts/build-bridge.sh"],
92
+ "output": "mcp/entwurf-bridge/dist"
93
+ }
94
+ },
95
+ {
96
+ "claim": "PI-DURABLE-RUNTIME-CONFIG-NEUTRAL",
97
+ "title": "the diff's blank-context spacing is left to the runtime's git configuration again, so a config can move the verdict",
98
+ "subject": "pi-extensions/lib/pi-durable-runtime.ts",
99
+ "find": [
100
+ "[\"-c\", \"core.abbrev=8\", \"-c\", \"diff.suppressBlankEmpty=false\", \"diff\", ...PI_DURABLE_DIFF_SHAPE]"
101
+ ],
102
+ "replace": ["[\"-c\", \"core.abbrev=8\", \"diff\", ...PI_DURABLE_DIFF_SHAPE]"],
103
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
104
+ "timeoutSeconds": 300,
105
+ "signature": "[QK:PI-DURABLE-RUNTIME-CONFIG-NEUTRAL]",
106
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
107
+ "build": {
108
+ "argv": ["bash", "scripts/build-bridge.sh"],
109
+ "output": "mcp/entwurf-bridge/dist"
110
+ }
111
+ },
112
+ {
113
+ "claim": "PI-DURABLE-RUNTIME-GATES-CONSUME-INDEX-TERM",
114
+ "title": "the contact gate's tracked-overlay assertion loses the index term, so it certifies a runtime tree it never saw",
115
+ "subject": "scripts/check-pi-durable-contact.ts",
116
+ "find": ["facts.gitAnswered && facts.indexMatchesHead && facts.diffEqualsPatch && facts.untracked"],
117
+ "replace": ["facts.gitAnswered && facts.diffEqualsPatch && facts.untracked"],
118
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
119
+ "timeoutSeconds": 300,
120
+ "signature": "[QK:PI-DURABLE-RUNTIME-GATES-CONSUME-INDEX-TERM]",
121
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
122
+ "build": {
123
+ "argv": ["bash", "scripts/build-bridge.sh"],
124
+ "output": "mcp/entwurf-bridge/dist"
125
+ }
126
+ },
127
+ {
128
+ "claim": "PI-DURABLE-PREFLIGHT-FOUR-UNITS",
129
+ "title": "the receive unit stops asking whether the compiled owner join admits the durable host, so a launch proceeds to a citizen nobody can deliver to",
130
+ "subject": "pi-extensions/lib/pi-durable-fresh-preflight.ts",
131
+ "find": [
132
+ "\tif (!ownerJoinAdmitsDurableHost(layout.deliverability)) return \"pi-durable-receive-unit-missing\";\n"
133
+ ],
134
+ "replace": [""],
135
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
136
+ "timeoutSeconds": 300,
137
+ "signature": "[QK:PI-DURABLE-PREFLIGHT-FOUR-UNITS]",
138
+ "signatureSource": "pi-extensions/lib/pi-durable-fresh-preflight.test.ts",
139
+ "build": {
140
+ "argv": ["bash", "scripts/build-bridge.sh"],
141
+ "output": "mcp/entwurf-bridge/dist"
142
+ }
143
+ },
144
+ {
145
+ "claim": "PI-DURABLE-PREFLIGHT-MODEL-QUALIFIED",
146
+ "title": "a model without a provider part passes the preflight and reaches the durable launch",
147
+ "subject": "pi-extensions/lib/pi-durable-fresh-preflight.ts",
148
+ "find": ["\tif (at <= 0 || at === model.length - 1) return null;"],
149
+ "replace": ["\tif (at < 0 || at === model.length - 1) return null;"],
150
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
151
+ "timeoutSeconds": 300,
152
+ "signature": "[QK:PI-DURABLE-PREFLIGHT-MODEL-QUALIFIED]",
153
+ "signatureSource": "pi-extensions/lib/pi-durable-fresh-preflight.test.ts",
154
+ "build": {
155
+ "argv": ["bash", "scripts/build-bridge.sh"],
156
+ "output": "mcp/entwurf-bridge/dist"
157
+ }
158
+ },
159
+ {
160
+ "claim": "PI-DURABLE-BOOTSTRAP-ARGV-NO-BRIDGE-ENTRY",
161
+ "title": "the launch argv accepts --bridge-entry, so a caller can point the contact at a bridge outside this package",
162
+ "subject": "pi/pi-durable/bootstrap.mjs",
163
+ "find": ["const VALUE_FLAGS = [\"--provider\", \"--model\", \"--width\", \"--entwurf-bootstrap\"];"],
164
+ "replace": [
165
+ "const VALUE_FLAGS = [\"--bridge-entry\", \"--provider\", \"--model\", \"--width\", \"--entwurf-bootstrap\"];"
166
+ ],
167
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
168
+ "timeoutSeconds": 300,
169
+ "signature": "[QK:PI-DURABLE-BOOTSTRAP-ARGV-NO-BRIDGE-ENTRY]",
170
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
171
+ "build": {
172
+ "argv": ["bash", "scripts/build-bridge.sh"],
173
+ "output": "mcp/entwurf-bridge/dist"
174
+ }
175
+ },
176
+ {
177
+ "claim": "PI-DURABLE-FRESH-CALL-EXPOSED",
178
+ "title": "entwurf_fresh_call drops out of the durable contact's tools, so the citizen cannot open a sibling",
179
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
180
+ "find": ["\t\ttools: PI_DURABLE_TOOL_NAMES.map(tool),"],
181
+ "replace": ["\t\ttools: PI_DURABLE_TOOL_NAMES.filter((name) => name !== \"entwurf_fresh_call\").map(tool),"],
182
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
183
+ "timeoutSeconds": 300,
184
+ "signature": "[QK:PI-DURABLE-FRESH-CALL-EXPOSED]",
185
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
186
+ "build": {
187
+ "argv": ["bash", "scripts/build-bridge.sh"],
188
+ "output": "mcp/entwurf-bridge/dist"
189
+ }
190
+ },
191
+ {
192
+ "claim": "PI-DURABLE-BRIDGE-DIRECT-SCRUBBED",
193
+ "title": "the identity scrub is omitted, so inherited identity carriers reach the bridge child",
194
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
195
+ "find": ["\t\tif (value !== undefined && !scrubbed.has(key)) env[key] = value;\n"],
196
+ "replace": ["\t\tif (value !== undefined) env[key] = value;\n"],
197
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
198
+ "timeoutSeconds": 300,
199
+ "signature": "[QK:PI-DURABLE-BRIDGE-DIRECT-SCRUBBED]",
200
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
201
+ "build": {
202
+ "argv": ["bash", "scripts/build-bridge.sh"],
203
+ "output": "mcp/entwurf-bridge/dist"
204
+ }
205
+ },
206
+ {
207
+ "claim": "PI-DURABLE-CHILD-ROOTS-ARE-WRITTEN-ROOTS",
208
+ "title": "the root binding is omitted, so the bridge child reads whatever garden roots it inherited instead of the roots the contact wrote",
209
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
210
+ "find": [
211
+ "\tfor (const key of Object.keys(PI_DURABLE_BRIDGE_ROOT_ENV) as (keyof PiDurableRoots)[]) {\n\t\tenv[PI_DURABLE_BRIDGE_ROOT_ENV[key]] = roots[key];\n\t}\n"
212
+ ],
213
+ "replace": [""],
214
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
215
+ "timeoutSeconds": 300,
216
+ "signature": "[QK:PI-DURABLE-CHILD-ROOTS-ARE-WRITTEN-ROOTS]",
217
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
218
+ "build": {
219
+ "argv": ["bash", "scripts/build-bridge.sh"],
220
+ "output": "mcp/entwurf-bridge/dist"
221
+ }
222
+ },
223
+ {
224
+ "claim": "PDH-JOIN-FOREIGN-SENDER-REFUSED",
225
+ "title": "the durable host leaves the sender join, so a live durable receiver whose owner sender marker names another garden is no longer refused (ABSENT-SENDER and SCOPE also go red)",
226
+ "subject": "pi-extensions/lib/entwurf-deliverability.ts",
227
+ "find": [
228
+ "export const SENDER_JOINED_RECEIVER_OWNER_KINDS: readonly string[] = [\"claude-code-cli\", \"pi-durable-host\"];"
229
+ ],
230
+ "replace": ["export const SENDER_JOINED_RECEIVER_OWNER_KINDS: readonly string[] = [\"claude-code-cli\"];"],
231
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
232
+ "timeoutSeconds": 300,
233
+ "signature": "[QK:PDH-JOIN-FOREIGN-SENDER-REFUSED]",
234
+ "signatureSource": "pi-extensions/lib/entwurf-deliverability.owner-join.test.ts",
235
+ "build": {
236
+ "argv": ["bash", "scripts/build-bridge.sh"],
237
+ "output": "mcp/entwurf-bridge/dist"
238
+ }
239
+ },
240
+ {
241
+ "claim": "PI-DURABLE-SCHEMA-DRIFT-REFUSED",
242
+ "title": "schema drift is never reported, so a bridge whose tool schemas differ from the exposed copies is accepted at birth",
243
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
244
+ "find": ["\treturn problems.length === 0 ? undefined : problems.join(\"; \");"],
245
+ "replace": ["\treturn undefined;"],
246
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
247
+ "timeoutSeconds": 300,
248
+ "signature": "[QK:PI-DURABLE-SCHEMA-DRIFT-REFUSED]",
249
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
250
+ "build": {
251
+ "argv": ["bash", "scripts/build-bridge.sh"],
252
+ "output": "mcp/entwurf-bridge/dist"
253
+ }
254
+ },
255
+ {
256
+ "claim": "PI-DURABLE-RECEIVER-REFUSES-UNVERIFIED-IDENTITY",
257
+ "title": "the receiver arms against any live sender marker, even one naming another garden or session",
258
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
259
+ "find": [
260
+ "\t\t\tif (sender === null || sender.gardenId !== gardenId || sender.nativeSessionId !== nativeSessionId) {"
261
+ ],
262
+ "replace": [
263
+ "\t\t\tif (sender === null || (sender.gardenId !== gardenId && sender.nativeSessionId !== nativeSessionId)) {"
264
+ ],
265
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
266
+ "timeoutSeconds": 300,
267
+ "signature": "[QK:PI-DURABLE-RECEIVER-REFUSES-UNVERIFIED-IDENTITY]",
268
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
269
+ "build": {
270
+ "argv": ["bash", "scripts/build-bridge.sh"],
271
+ "output": "mcp/entwurf-bridge/dist"
272
+ }
273
+ },
274
+ {
275
+ "claim": "PI-DURABLE-ONE-BIRTH",
276
+ "title": "a born contact can attach again, minting a second birth on the same contact",
277
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
278
+ "find": [
279
+ "\t\t\tif (state.kind !== \"pending\") {\n\t\t\t\tthrow new Error(`pi-durable contact: attach is a one-time birth"
280
+ ],
281
+ "replace": [
282
+ "\t\t\tif (state.kind === \"attaching\") {\n\t\t\t\tthrow new Error(`pi-durable contact: attach is a one-time birth"
283
+ ],
284
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
285
+ "timeoutSeconds": 300,
286
+ "signature": "[QK:PI-DURABLE-ONE-BIRTH]",
287
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
288
+ "build": {
289
+ "argv": ["bash", "scripts/build-bridge.sh"],
290
+ "output": "mcp/entwurf-bridge/dist"
291
+ }
292
+ },
293
+ {
294
+ "claim": "PI-DURABLE-FIRST-INPUT-ONCE",
295
+ "title": "the launcher's first input loses its fixed request id, so a reopen can admit the same task again",
296
+ "subject": "pi/pi-durable/bootstrap.mjs",
297
+ "find": ["\t\t\t\trequestId: `entwurf-first-input:${attachment.gardenId}`,\n"],
298
+ "replace": [""],
299
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
300
+ "timeoutSeconds": 300,
301
+ "signature": "[QK:PI-DURABLE-FIRST-INPUT-ONCE]",
302
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
303
+ "build": {
304
+ "argv": ["bash", "scripts/build-bridge.sh"],
305
+ "output": "mcp/entwurf-bridge/dist"
306
+ }
307
+ },
308
+ {
309
+ "claim": "PI-DURABLE-GATE-SEND-OWNS-QUALIFIED-START",
310
+ "title": "the send gate registers a bridge under a fresh start read instead of the start that qualified it, so a pid recycled after qualification is owned and signalled",
311
+ "subject": "scripts/check-pi-durable-send.ts",
312
+ "find": ["own(child.pid, \"bridge\", child.start)"],
313
+ "replace": ["own(child.pid, \"bridge\")"],
314
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
315
+ "timeoutSeconds": 300,
316
+ "signature": "[QK:PI-DURABLE-GATE-SEND-OWNS-QUALIFIED-START]",
317
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
318
+ "build": {
319
+ "argv": ["bash", "scripts/build-bridge.sh"],
320
+ "output": "mcp/entwurf-bridge/dist"
321
+ }
322
+ },
323
+ {
324
+ "claim": "PI-DURABLE-GATE-SEND-OBSERVED-BY-IDENTITY",
325
+ "title": "the send gate looks complete observation up by pid, so a host whose pid was reused inherits its predecessor's observed children",
326
+ "subject": "scripts/check-pi-durable-send.ts",
327
+ "find": ["childrenObserved.has(host)"],
328
+ "replace": ["[...childrenObserved].some((h) => h.pid === host.pid)"],
329
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
330
+ "timeoutSeconds": 300,
331
+ "signature": "[QK:PI-DURABLE-GATE-SEND-OBSERVED-BY-IDENTITY]",
332
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
333
+ "build": {
334
+ "argv": ["bash", "scripts/build-bridge.sh"],
335
+ "output": "mcp/entwurf-bridge/dist"
336
+ }
337
+ },
338
+ {
339
+ "claim": "PI-DURABLE-GATE-SEND-S3-START-RECHECKED",
340
+ "title": "the send gate's SIGKILL of the paused bridge loses its start-key re-check, so a process that replaced it after the IO and state reads is killed",
341
+ "subject": "scripts/check-pi-durable-send.ts",
342
+ "find": [
343
+ "\tif (procStat(bridge1.pid)?.start !== bridge1.start)\n\t\tthrow new Error(`GAP: bridge1 ${bridge1.pid} is not the observed process immediately before its SIGKILL`);\n"
344
+ ],
345
+ "replace": [""],
346
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
347
+ "timeoutSeconds": 300,
348
+ "signature": "[QK:PI-DURABLE-GATE-SEND-S3-START-RECHECKED]",
349
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
350
+ "build": {
351
+ "argv": ["bash", "scripts/build-bridge.sh"],
352
+ "output": "mcp/entwurf-bridge/dist"
353
+ }
354
+ },
355
+ {
356
+ "claim": "PI-DURABLE-GATE-RECEIVE-CONNECT-CLOSES",
357
+ "title": "the receive gate's failed connect no longer closes the transport, so a bridge spawned inside connect is left neither owned nor closed",
358
+ "subject": "scripts/check-pi-durable-receive.ts",
359
+ "find": [
360
+ "\ttry {\n\t\tawait client.connect(transport);\n\t} catch (error) {\n\t\t// A failed connect may already have spawned the bridge, which is not owned yet: close the\n\t\t// transport (it ends the child it spawned) before rethrowing, and keep the cause first.\n\t\ttry {\n\t\t\tawait transport.close();\n\t\t} catch (closeError) {\n\t\t\tthrow new AggregateError(\n\t\t\t\t[error, closeError],\n\t\t\t\t`the sending bridge did not connect (${(error as Error).message}); closing it also failed`,\n\t\t\t);\n\t\t}\n\t\tthrow error;\n\t}\n"
361
+ ],
362
+ "replace": ["\tawait client.connect(transport);\n"],
363
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
364
+ "timeoutSeconds": 300,
365
+ "signature": "[QK:PI-DURABLE-GATE-RECEIVE-CONNECT-CLOSES]",
366
+ "signatureSource": "pi-extensions/lib/pi-durable-runtime.test.ts",
367
+ "build": {
368
+ "argv": ["bash", "scripts/build-bridge.sh"],
369
+ "output": "mcp/entwurf-bridge/dist"
370
+ }
371
+ },
372
+ {
373
+ "claim": "PI-DURABLE-RECEIVER-DIAGNOSTIC-LATEST-ONLY",
374
+ "title": "the receiver diagnostic appends every successful admission instead of keeping the latest one, so it grows with the host's lifetime (RING-COALESCES, whose two-pass expectation is latest-only, also goes red)",
375
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
376
+ "find": [
377
+ "\t\t\t\tadmissions.splice(0, admissions.length, { why, requestId, submissionId: submission.id, fresh, unread });"
378
+ ],
379
+ "replace": ["\t\t\t\tadmissions.push({ why, requestId, submissionId: submission.id, fresh, unread });"],
380
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
381
+ "timeoutSeconds": 300,
382
+ "signature": "[QK:PI-DURABLE-RECEIVER-DIAGNOSTIC-LATEST-ONLY]",
383
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
384
+ "build": {
385
+ "argv": ["bash", "scripts/build-bridge.sh"],
386
+ "output": "mcp/entwurf-bridge/dist"
387
+ }
388
+ }
389
+ ]
390
+ }
@@ -7,10 +7,10 @@
7
7
  "title": "one row of the pnpm workspace closure is left on the previous floor while every other surface moved — the shape a version bump actually fails in. Nothing else reads that file, so the stranded row surfaces only at install time, in a different command, far from the change that stranded it",
8
8
  "subject": "pnpm-workspace.yaml",
9
9
  "find": [
10
- " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2 || 1.0.0'"
10
+ " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2 || 1.0.0 || 1.0.2'"
11
11
  ],
12
12
  "replace": [
13
- " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2'"
13
+ " - '@earendil-works/pi-telemetry@0.85.0 || 0.85.1 || 0.86.0 || 0.87.0 || 0.87.1 || 0.99.1 || 0.99.2 || 1.0.0'"
14
14
  ],
15
15
  "gate": ["bash", "run.sh", "check-dep-versions"],
16
16
  "timeoutSeconds": 300,