@junghanacs/entwurf 0.40.0 → 0.41.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.
Files changed (128) hide show
  1. package/AGENTS.md +4 -2
  2. package/BASELINE.md +55 -2
  3. package/CHANGELOG.md +562 -0
  4. package/CONTRIBUTING.md +1 -1
  5. package/DELIVERY.md +18 -2
  6. package/FAQ.md +8 -4
  7. package/README.md +60 -45
  8. package/VERIFY.md +14 -11
  9. package/demo/README.md +1 -1
  10. package/docs/acp-backend-rail.md +6 -2
  11. package/docs/external-mcp-host.md +8 -6
  12. package/docs/fresh-cut-policy.md +9 -1
  13. package/docs/setup-clean-host.md +76 -20
  14. package/mcp/entwurf-bridge/dist/mcp/entwurf-bridge/src/index.js +81 -19
  15. package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-pidfd.py +236 -0
  16. package/mcp/entwurf-bridge/dist/pi-extensions/lib/cc-retire-request.js +473 -0
  17. package/mcp/entwurf-bridge/dist/pi-extensions/lib/control-retire.js +125 -0
  18. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire-production.js +149 -0
  19. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-retire.js +158 -0
  20. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-surface.js +2 -1
  21. package/mcp/entwurf-bridge/dist/pi-extensions/lib/entwurf-v2-visible-resume.js +283 -20
  22. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-composition.js +7 -0
  23. package/mcp/entwurf-bridge/dist/pi-extensions/lib/fresh-call-dispatch.js +47 -3
  24. package/mcp/entwurf-bridge/dist/pi-extensions/lib/herdr-fresh-call.js +3 -1
  25. package/mcp/entwurf-bridge/dist/pi-extensions/lib/meta-session.js +96 -16
  26. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-fresh-call.js +5 -29
  27. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-launch.js +28 -0
  28. package/mcp/entwurf-bridge/dist/pi-extensions/lib/mux-resume-call.js +26 -11
  29. package/mcp/entwurf-bridge/dist/pi-extensions/lib/pi-retire-request.js +76 -0
  30. package/mcp/entwurf-bridge/dist/pi-extensions/lib/resume-launch-identity.js +67 -17
  31. package/mcp/entwurf-bridge/dist/pi-extensions/lib/retirement-event.js +211 -0
  32. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-hook.js +124 -10
  33. package/mcp/entwurf-bridge/dist/pi-extensions/meta-bridge-pi-durable.js +53 -2
  34. package/mcp/entwurf-bridge/dist/scripts/meta-facts.js +1 -1
  35. package/mcp/entwurf-bridge/dist/scripts/probe-bridge-command.js +1 -0
  36. package/mcp/entwurf-bridge/src/index.ts +93 -19
  37. package/mcp/entwurf-bridge/test.sh +2 -2
  38. package/mcp/entwurf-bridge/tsconfig.build.json +10 -1
  39. package/package.json +15 -14
  40. package/pi/meta-bridge/entwurf-meta-receive/scripts/hook-launch.sh +3 -3
  41. package/pi/pi-durable/carrier/tui.js +18 -3
  42. package/pi/pi-durable/overlay/upstream-pin.json +12 -12
  43. package/pi-extensions/entwurf-control.ts +55 -20
  44. package/pi-extensions/lib/acp/backend-adapter.ts +5 -3
  45. package/pi-extensions/lib/acp/backend.ts +12 -9
  46. package/pi-extensions/lib/cc-retire-pidfd.py +236 -0
  47. package/pi-extensions/lib/cc-retire-request.ts +553 -0
  48. package/pi-extensions/lib/control-retire.ts +195 -0
  49. package/pi-extensions/lib/entwurf-control-rpc.ts +17 -1
  50. package/pi-extensions/lib/entwurf-v2-retire-production.ts +227 -0
  51. package/pi-extensions/lib/entwurf-v2-retire.ts +269 -0
  52. package/pi-extensions/lib/entwurf-v2-surface.ts +2 -1
  53. package/pi-extensions/lib/entwurf-v2-visible-resume.ts +390 -36
  54. package/pi-extensions/lib/fresh-call-composition.ts +15 -0
  55. package/pi-extensions/lib/fresh-call-dispatch.ts +45 -4
  56. package/pi-extensions/lib/herdr-fresh-call.ts +5 -0
  57. package/pi-extensions/lib/meta-session.ts +140 -16
  58. package/pi-extensions/lib/mux-fresh-call.ts +7 -27
  59. package/pi-extensions/lib/mux-launch.ts +29 -0
  60. package/pi-extensions/lib/mux-resume-call.ts +33 -12
  61. package/pi-extensions/lib/pi-retire-request.ts +111 -0
  62. package/pi-extensions/lib/resume-launch-identity.ts +104 -18
  63. package/pi-extensions/lib/retirement-event.ts +253 -0
  64. package/pi-extensions/meta-bridge-hook.ts +142 -13
  65. package/pi-extensions/meta-bridge-pi-durable.ts +57 -3
  66. package/run.sh +123 -34
  67. package/scripts/agy-bridge-config.py +4 -1
  68. package/scripts/build-bridge.sh +14 -0
  69. package/scripts/check-capability-bundle-reach.ts +135 -2
  70. package/scripts/check-entwurf-bridge-boot.ts +2 -1
  71. package/scripts/check-entwurf-fact-provider.ts +1 -0
  72. package/scripts/check-entwurf-v2-production.ts +2 -0
  73. package/scripts/check-entwurf-v2-surface.ts +7 -0
  74. package/scripts/check-gate-qualification.ts +14 -8
  75. package/scripts/check-herdr-activation.ts +2 -2
  76. package/scripts/check-herdr-placement.ts +1 -0
  77. package/scripts/check-hook-launch-topology.ts +6 -15
  78. package/scripts/check-install-container.sh +2 -2
  79. package/scripts/check-meta-doctor-oracle.sh +27 -1
  80. package/scripts/check-meta-facts.ts +8 -3
  81. package/scripts/check-meta-hook-session-switch.ts +230 -13
  82. package/scripts/check-meta-identity-consumers.ts +1 -0
  83. package/scripts/check-meta-listing.ts +1 -0
  84. package/scripts/check-meta-manifest-schema.py +1 -1
  85. package/scripts/check-meta-session.ts +31 -0
  86. package/scripts/check-meta-v3-record.ts +55 -1
  87. package/scripts/check-mux-resume-call.ts +35 -9
  88. package/scripts/check-peer-facts.ts +1 -0
  89. package/scripts/check-pi-durable-contact.ts +3 -1
  90. package/scripts/check-pi-durable-send.ts +4 -2
  91. package/scripts/check-pi-mcp-bridge.ts +1 -0
  92. package/scripts/check-resume-launch-identity.ts +62 -23
  93. package/scripts/lib/codex-fresh-live-protocol.ts +3 -2
  94. package/scripts/lib/meta-hook-bundle.ts +72 -0
  95. package/scripts/meta-bridge-claude-floor.sh +13 -9
  96. package/scripts/meta-bridge-doctor.sh +17 -0
  97. package/scripts/meta-bridge-install.sh +6 -0
  98. package/scripts/meta-facts.ts +1 -1
  99. package/scripts/mutants/bridge-boot-resume.json +5 -2
  100. package/scripts/mutants/cc-retire-pidfd.json +129 -0
  101. package/scripts/mutants/cc-retire-request.json +171 -0
  102. package/scripts/mutants/control-retire.json +105 -0
  103. package/scripts/mutants/control-send-receipt.json +1 -1
  104. package/scripts/mutants/copilot-receive.json +2 -6
  105. package/scripts/mutants/entwurf-v2-retire.json +476 -0
  106. package/scripts/mutants/fresh-call-dispatch.json +37 -0
  107. package/scripts/mutants/meta-hook-session-switch.json +88 -0
  108. package/scripts/mutants/meta-identity.json +57 -0
  109. package/scripts/mutants/mux-fresh-call.json +1 -1
  110. package/scripts/mutants/mux-resume-call.json +40 -4
  111. package/scripts/mutants/pack-install.json +4 -4
  112. package/scripts/mutants/pi-durable.json +139 -0
  113. package/scripts/mutants/pi-floor.json +5 -5
  114. package/scripts/mutants/pi-retire-request.json +72 -0
  115. package/scripts/mutants/resume-launch-identity.json +35 -8
  116. package/scripts/mutants/retirement-event.json +195 -0
  117. package/scripts/mutants/v2-surface.json +16 -0
  118. package/scripts/mutants/v2-visible-resume.json +283 -13
  119. package/scripts/probe-bridge-command.ts +1 -0
  120. package/scripts/smoke-agy-install-state.sh +2 -2
  121. package/scripts/smoke-codex-fresh-live.ts +2 -1
  122. package/scripts/smoke-copilot-mcp-state.sh +1 -1
  123. package/scripts/smoke-herdr-raw-install-live.sh +15 -7
  124. package/scripts/smoke-meta-install-state.sh +4 -4
  125. package/scripts/smoke-mux-lifecycle-live.ts +10 -10
  126. package/scripts/smoke-omp-mcp-state.sh +1 -1
  127. package/scripts/smoke-pi-durable-fresh-live.ts +5 -3
  128. package/scripts/smoke-pi-provider-state.sh +3 -3
@@ -48,6 +48,63 @@
48
48
  "timeoutSeconds": 120,
49
49
  "signature": "[QK:META-CREATE-PUBLISHED-CLEANUP]",
50
50
  "signatureSource": "scripts/check-meta-session.ts"
51
+ },
52
+ {
53
+ "claim": "META-V3-INCARNATION-ABSENT-NULL",
54
+ "title": "a V3 body without attachIncarnation is refused, so every untouched record becomes unreadable",
55
+ "subject": "pi-extensions/lib/meta-session.ts",
56
+ "find": [
57
+ "\t\tattachIncarnation: requireAttachIncarnation(obj.attachIncarnation === undefined ? null : obj.attachIncarnation),"
58
+ ],
59
+ "replace": ["\t\tattachIncarnation: requireAttachIncarnation(obj.attachIncarnation),"],
60
+ "gate": ["bash", "run.sh", "check-meta-v3-record"],
61
+ "timeoutSeconds": 120,
62
+ "signature": "[QK:META-V3-INCARNATION-ABSENT-NULL]",
63
+ "signatureSource": "scripts/check-meta-v3-record.ts"
64
+ },
65
+ {
66
+ "claim": "META-V3-INCARNATION-MALFORMED",
67
+ "title": "any string is accepted as a binding",
68
+ "subject": "pi-extensions/lib/meta-session.ts",
69
+ "find": ["\tif (typeof value !== \"string\" || !ATTACH_INCARNATION_RE.test(value)) {"],
70
+ "replace": ["\tif (typeof value !== \"string\") {"],
71
+ "gate": ["bash", "run.sh", "check-meta-v3-record"],
72
+ "timeoutSeconds": 120,
73
+ "signature": "[QK:META-V3-INCARNATION-MALFORMED]",
74
+ "signatureSource": "scripts/check-meta-v3-record.ts"
75
+ },
76
+ {
77
+ "claim": "META-V3-INCARNATION-ALWAYS-EMITTED",
78
+ "title": "the serializer drops attachIncarnation, so a committed binding never reaches disk",
79
+ "subject": "pi-extensions/lib/meta-session.ts",
80
+ "find": ["\t\tattachIncarnation: identity.attachIncarnation,"],
81
+ "replace": [""],
82
+ "gate": ["bash", "run.sh", "check-meta-v3-record"],
83
+ "timeoutSeconds": 120,
84
+ "signature": "[QK:META-V3-INCARNATION-ALWAYS-EMITTED]",
85
+ "signatureSource": "scripts/check-meta-v3-record.ts"
86
+ },
87
+ {
88
+ "claim": "META-UPSERT-PRESERVES-INCARNATION",
89
+ "title": "an attach that does not mint clears the binding",
90
+ "subject": "pi-extensions/lib/meta-session.ts",
91
+ "find": ["\t\t\t? existing.attachIncarnation"],
92
+ "replace": ["\t\t\t? null"],
93
+ "gate": ["bash", "run.sh", "check-meta-v3-record"],
94
+ "timeoutSeconds": 120,
95
+ "signature": "[QK:META-UPSERT-PRESERVES-INCARNATION]",
96
+ "signatureSource": "scripts/check-meta-v3-record.ts"
97
+ },
98
+ {
99
+ "claim": "META-UPSERT-EXPECT-ACTION",
100
+ "title": "upsert ignores expectAction, so a raced create silently becomes an unlocked attach",
101
+ "subject": "pi-extensions/lib/meta-session.ts",
102
+ "find": ["\tif (opts.expectAction !== undefined && decision.action !== opts.expectAction) {"],
103
+ "replace": ["\tif (false) {"],
104
+ "gate": ["bash", "run.sh", "check-meta-session"],
105
+ "timeoutSeconds": 120,
106
+ "signature": "[QK:META-UPSERT-EXPECT-ACTION]",
107
+ "signatureSource": "scripts/check-meta-session.ts"
51
108
  }
52
109
  ]
53
110
  }
@@ -151,7 +151,7 @@
151
151
  "title": "MCP drops the required model field from fresh-call while the composition still expects one",
152
152
  "subject": "mcp/entwurf-bridge/src/index.ts",
153
153
  "find": [
154
- "\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi, provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name.\",\n\t\t\t),\n"
154
+ "\t\tmodel: z\n\t\t\t.string()\n\t\t\t.min(1)\n\t\t\t.max(200)\n\t\t\t// The `\\[` below is USELESS TO JS AND LOAD-BEARING TO THE HOST. zod emits this source\n\t\t\t// text verbatim as the JSON Schema `pattern`, and the host's tool-schema validator is a\n\t\t\t// Rust regex engine that rejects an unescaped `[` inside a character class as \"unclosed\n\t\t\t// character class\" — a 400 on tools/list that stops EVERY Claude session from opening\n\t\t\t// (7-M-fix). Biome's safe fix removes it; do not accept that fix. The suppression must\n\t\t\t// stay on the line DIRECTLY above the expression, or it attaches to nothing and reads\n\t\t\t// as an unused suppression while the escape goes back to being fixable.\n\t\t\t// biome-ignore lint/complexity/noUselessEscapeInRegex: emitted to a Rust regex validator, see above\n\t\t\t.regex(/^[A-Za-z0-9][A-Za-z0-9._/:\\[\\]-]*$/)\n\t\t\t.describe(\n\t\t\t\t\"Required runtime model: canonical provider/model for pi (a bare alias is refused), provider/<exact catalog model id> for pi-durable, a Claude Code model id/alias, or a Copilot/OMP/Codex model name. Neither pi nor pi-durable may name the openrouter provider.\",\n\t\t\t),\n"
155
155
  ],
156
156
  "replace": [""],
157
157
  "gate": ["bash", "run.sh", "check-mux-fresh-call"],
@@ -72,8 +72,11 @@
72
72
  "claim": "MUXRESUME-NO-IDENTITY",
73
73
  "title": "identity vocabulary enters the placement module, which is the first step of a leaf learning whose citizen it is opening",
74
74
  "subject": "pi-extensions/lib/mux-resume-call.ts",
75
- "find": ["export const RESUME_CALL_RUNTIME = \"pi\";"],
76
- "replace": ["export const RESUME_CALL_RUNTIME = \"pi\";\nexport const RESUME_CALL_TARGET_KEY = \"gardenId\";"],
75
+ "find": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;"],
76
+ "replace": [
77
+ "export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;",
78
+ "export const RESUME_CALL_TARGET_KEY = \"gardenId\";"
79
+ ],
77
80
  "gate": ["bash", "run.sh", "check-mux-resume-call"],
78
81
  "timeoutSeconds": 60,
79
82
  "signature": "[QK:MUXRESUME-NO-IDENTITY]",
@@ -97,10 +100,10 @@
97
100
  "title": "the MCP description drops the dormant-only scope, inviting callers to aim the verb at live citizens it will refuse",
98
101
  "subject": "mcp/entwurf-bridge/src/index.ts",
99
102
  "find": [
100
- "\t\"Reopen ONE DORMANT pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
103
+ "\t\"Reopen ONE DORMANT pi or Claude Code citizen under its OWN garden id, in a visible window in the operator's \" +"
101
104
  ],
102
105
  "replace": [
103
- "\t\"Reopen ONE pi citizen under its OWN garden id, in a visible window in the operator's own tmux \""
106
+ "\t\"Reopen ONE pi or Claude Code citizen under its OWN garden id, in a visible window in the operator's \" +"
104
107
  ],
105
108
  "gate": ["bash", "run.sh", "check-mux-resume-call"],
106
109
  "timeoutSeconds": 60,
@@ -119,6 +122,39 @@
119
122
  "timeoutSeconds": 60,
120
123
  "signature": "[QK:MUXRESUME-MCP-TARGET-PASSTHROUGH]",
121
124
  "signatureSource": "scripts/check-mux-resume-call.ts"
125
+ },
126
+ {
127
+ "claim": "MUXRESUME-RUNTIME-TABLE",
128
+ "title": "a Claude Code resume is started under pi, so the window opens the wrong runtime on the right session id",
129
+ "subject": "pi-extensions/lib/mux-resume-call.ts",
130
+ "find": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"claude\" } as const;"],
131
+ "replace": ["export const RESUME_CALL_RUNTIME = { pi: \"pi\", \"claude-code\": \"pi\" } as const;"],
132
+ "gate": ["bash", "run.sh", "check-mux-resume-call"],
133
+ "timeoutSeconds": 60,
134
+ "signature": "[QK:MUXRESUME-RUNTIME-TABLE]",
135
+ "signatureSource": "scripts/check-mux-resume-call.ts"
136
+ },
137
+ {
138
+ "claim": "MUXRESUME-HERDR-REFUSED",
139
+ "title": "inside herdr the tmux resume rail no longer refuses, so an ambient TMUX opens the window where the operator is not looking",
140
+ "subject": "pi-extensions/lib/mux-resume-call.ts",
141
+ "find": ["\tif (env.HERDR_ENV === \"1\") return { ok: false, reason: \"herdr-resume-unsupported\" };"],
142
+ "replace": [""],
143
+ "gate": ["bash", "run.sh", "check-mux-resume-call"],
144
+ "timeoutSeconds": 60,
145
+ "signature": "[QK:MUXRESUME-HERDR-REFUSED]",
146
+ "signatureSource": "scripts/check-mux-resume-call.ts"
147
+ },
148
+ {
149
+ "claim": "MUXRESUME-ARGV-IDENTITY-SCRUB",
150
+ "title": "the resume window stops emptying the inherited pi identity carriers, so a resumed Claude Code presents a stale identity to its bridge",
151
+ "subject": "pi-extensions/lib/mux-resume-call.ts",
152
+ "find": ["\t\t...SCRUBBED_INHERITED_ENV.flatMap((assignment) => [\"-e\", assignment]),"],
153
+ "replace": [""],
154
+ "gate": ["bash", "run.sh", "check-mux-resume-call"],
155
+ "timeoutSeconds": 60,
156
+ "signature": "[QK:MUXRESUME-ARGV-IDENTITY-SCRUB]",
157
+ "signatureSource": "scripts/check-mux-resume-call.ts"
122
158
  }
123
159
  ]
124
160
  }
@@ -6,8 +6,8 @@
6
6
  "claim": "PACK-INSTALL-PIN-MATCHER-BOUNDED",
7
7
  "title": "the pin-leak matcher loses its version boundary and blesses substring lookalikes \u2014 @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\\.3\\.0(_|$)' || true"],
10
- "replace": [" grep '^@earendil-works+' | grep -v '@0\\.87\\.1' || true"],
9
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.4\\.0(_|$)' || true"],
10
+ "replace": [" grep '^@earendil-works+' | grep -v '@1\\.4\\.0' || true"],
11
11
  "gate": ["bash", "run.sh", "check-pack-pin-matcher"],
12
12
  "timeoutSeconds": 120,
13
13
  "signature": "[QK:PACK-INSTALL-PIN-MATCHER-BOUNDED]",
@@ -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 \u2014 @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\\.3\\.0(_|$)' || true"],
21
- "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@1\\.3\\.0(_|$)' || true"],
20
+ "find": [" grep '^@earendil-works+' | grep -Ev '@1\\.4\\.0(_|$)' || true"],
21
+ "replace": [" grep '^@earendil-works+pi-' | grep -Ev '@1\\.4\\.0(_|$)' || 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]",
@@ -2,6 +2,61 @@
2
2
  "schemaVersion": 1,
3
3
  "lane": "pi-durable",
4
4
  "mutants": [
5
+ {
6
+ "claim": "PI-DURABLE-RETIRE-CALL",
7
+ "title": "retirement alone drops the actual request cancellation signal",
8
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
9
+ "find": [
10
+ "\t\t\tconst call = () => client.callTool(name, (args ?? {}) as Record<string, unknown>, context?.abortSignal);"
11
+ ],
12
+ "replace": [
13
+ "\t\t\tconst call = () => client.callTool(name, (args ?? {}) as Record<string, unknown>, name === \"entwurf_retire_call\" ? undefined : context?.abortSignal);"
14
+ ],
15
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
16
+ "timeoutSeconds": 300,
17
+ "signature": "[QK:PI-DURABLE-RETIRE-CALL]",
18
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
19
+ "build": {
20
+ "argv": ["bash", "scripts/build-bridge.sh"],
21
+ "output": "mcp/entwurf-bridge/dist"
22
+ }
23
+ },
24
+ {
25
+ "claim": "PI-DURABLE-RETIRE-POLICY",
26
+ "title": "the native retirement description treats actor identity as a standing grant",
27
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
28
+ "find": [
29
+ "\t\t\"Only when the human operator explicitly requested this particular target/work: make ONE retirement attempt for that request \" +"
30
+ ],
31
+ "replace": [
32
+ "\t\t\"A caller record alone authorizes this target/work: make ONE retirement attempt for that request \" +"
33
+ ],
34
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
35
+ "timeoutSeconds": 300,
36
+ "signature": "[QK:PI-DURABLE-RETIRE-POLICY]",
37
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
38
+ "build": {
39
+ "argv": ["bash", "scripts/build-bridge.sh"],
40
+ "output": "mcp/entwurf-bridge/dist"
41
+ }
42
+ },
43
+ {
44
+ "claim": "PI-DURABLE-RETIRE-CALL-REACHES-BRIDGE",
45
+ "title": "the compiled retirement handler discards the actual host-authoritative caller",
46
+ "subject": "mcp/entwurf-bridge/src/index.ts",
47
+ "find": [
48
+ "\t\t\t\t\tresolveCaller: async () => (await resolveAuthoritativeSender({ requestMeta: extra._meta }))?.envelope ?? null,"
49
+ ],
50
+ "replace": ["\t\t\t\t\tresolveCaller: async () => null,"],
51
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
52
+ "timeoutSeconds": 300,
53
+ "signature": "[QK:PI-DURABLE-RETIRE-CALL-REACHES-BRIDGE]",
54
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
55
+ "build": {
56
+ "argv": ["bash", "scripts/build-bridge.sh"],
57
+ "output": "mcp/entwurf-bridge/dist"
58
+ }
59
+ },
5
60
  {
6
61
  "claim": "PI-DURABLE-ENTRY-GUARD-FLOOR-SAFE",
7
62
  "title": "the verifier's entry guard goes back to import.meta.main, which the floor's runner can misread as the process entry",
@@ -1152,6 +1207,66 @@
1152
1207
  "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1153
1208
  "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1154
1209
  },
1210
+ {
1211
+ "claim": "PI-DURABLE-TASK-SLEEPING-COUNTED",
1212
+ "title": "the badge stops naming sleeping tasks: a background task in its durable backoff is counted but said to be nothing",
1213
+ "subject": "pi/pi-durable/carrier/tui.js",
1214
+ "find": ["\t\t\t...tally(\"sleeping\", (node) => !node.abortRequested && node.state.status === \"sleeping\"),"],
1215
+ "replace": ["\t\t\t// sleeping is not named"],
1216
+ "gate": ["bash", "run.sh", "check-pi-durable-carrier"],
1217
+ "timeoutSeconds": 300,
1218
+ "signature": "[QK:PI-DURABLE-TASK-SLEEPING-COUNTED]",
1219
+ "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1220
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1221
+ },
1222
+ {
1223
+ "claim": "PI-DURABLE-TASK-SLEEPING-SHOWN",
1224
+ "title": "a sleeping task's panel line drops its wake time, so nothing on screen says when the sleeping work comes back",
1225
+ "subject": "pi/pi-durable/carrier/tui.js",
1226
+ "find": ["\t\t\t\t\t? `sleeping ${state.phase} until ${localTime(state.until)}`"],
1227
+ "replace": ["\t\t\t\t\t? `sleeping ${state.phase}`"],
1228
+ "gate": ["bash", "run.sh", "check-pi-durable-carrier"],
1229
+ "timeoutSeconds": 300,
1230
+ "signature": "[QK:PI-DURABLE-TASK-SLEEPING-SHOWN]",
1231
+ "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1232
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1233
+ },
1234
+ {
1235
+ "claim": "PI-DURABLE-TASK-BLOCKED-SHOWN",
1236
+ "title": "the panel stops marking blocked tasks: a task the SDK will not run reads as ordinary pending work",
1237
+ "subject": "pi/pi-durable/carrier/tui.js",
1238
+ "find": ["\t\tnode.blocked !== undefined ? `blocked:${node.blocked}` : \"\","],
1239
+ "replace": ["\t\t\"\","],
1240
+ "gate": ["bash", "run.sh", "check-pi-durable-carrier"],
1241
+ "timeoutSeconds": 300,
1242
+ "signature": "[QK:PI-DURABLE-TASK-BLOCKED-SHOWN]",
1243
+ "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1244
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1245
+ },
1246
+ {
1247
+ "claim": "PI-DURABLE-TASK-BLOCKED-REASON",
1248
+ "title": "every blocked task is said to be parked by the restart limit, whatever reason the SDK gave",
1249
+ "subject": "pi/pi-durable/carrier/tui.js",
1250
+ "find": ["\t\tnode.blocked !== undefined ? `blocked:${node.blocked}` : \"\","],
1251
+ "replace": ["\t\tnode.blocked !== undefined ? `blocked:restart_limit` : \"\","],
1252
+ "gate": ["bash", "run.sh", "check-pi-durable-carrier"],
1253
+ "timeoutSeconds": 300,
1254
+ "signature": "[QK:PI-DURABLE-TASK-BLOCKED-REASON]",
1255
+ "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1256
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1257
+ },
1258
+ {
1259
+ "claim": "PI-DURABLE-TEST-FIXTURES-NOT-SHIPPED",
1260
+ "title": "package.json drops its fixture negation, so every published tarball carries the test goldens under pi-extensions/**/fixtures/",
1261
+ "subject": "package.json",
1262
+ "find": ["\t\t\"!pi-extensions/**/*.test.ts\",", "\t\t\"!pi-extensions/**/fixtures/**\""],
1263
+ "replace": ["\t\t\"!pi-extensions/**/*.test.ts\""],
1264
+ "gate": ["bash", "run.sh", "check-pi-durable-carrier"],
1265
+ "timeoutSeconds": 300,
1266
+ "signature": "[QK:PI-DURABLE-TEST-FIXTURES-NOT-SHIPPED]",
1267
+ "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1268
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1269
+ },
1155
1270
  {
1156
1271
  "claim": "PI-DURABLE-STREAM-TRANSPORT-WIRE",
1157
1272
  "title": "the Harness settings stop carrying the transport: the provider never continues a response, so every request of a long session resends the whole conversation",
@@ -1223,6 +1338,30 @@
1223
1338
  "signature": "[QK:PI-DURABLE-RESUME-CANCEL-OPENS-NOTHING]",
1224
1339
  "signatureSource": "pi-extensions/lib/pi-durable-carrier.test.ts",
1225
1340
  "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1341
+ },
1342
+ {
1343
+ "claim": "PI-DURABLE-RESUME-CALL-EXPOSED",
1344
+ "title": "entwurf_resume_call drops out of the durable contact's tools, so the coordinator citizen cannot reopen a dormant pi sibling",
1345
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
1346
+ "find": ["\t\ttools: PI_DURABLE_TOOL_NAMES.map(tool),"],
1347
+ "replace": ["\t\ttools: PI_DURABLE_TOOL_NAMES.filter((name) => name !== \"entwurf_resume_call\").map(tool),"],
1348
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
1349
+ "timeoutSeconds": 300,
1350
+ "signature": "[QK:PI-DURABLE-RESUME-CALL-EXPOSED]",
1351
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
1352
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1353
+ },
1354
+ {
1355
+ "claim": "PI-DURABLE-RESUME-CALL-REACHES-BRIDGE",
1356
+ "title": "the production stdio connector stops carrying a tool's arguments: every stub-bridge case still passes, but the real bridge never sees the target the model named",
1357
+ "subject": "pi-extensions/meta-bridge-pi-durable.ts",
1358
+ "find": ["const result = await client.callTool({ name, arguments: args }, undefined, { signal });"],
1359
+ "replace": ["const result = await client.callTool({ name, arguments: {} }, undefined, { signal });"],
1360
+ "gate": ["bash", "run.sh", "check-pi-durable-beside"],
1361
+ "timeoutSeconds": 300,
1362
+ "signature": "[QK:PI-DURABLE-RESUME-CALL-REACHES-BRIDGE]",
1363
+ "signatureSource": "pi-extensions/meta-bridge-pi-durable.test.ts",
1364
+ "build": { "argv": ["bash", "scripts/build-bridge.sh"], "output": "mcp/entwurf-bridge/dist" }
1226
1365
  }
1227
1366
  ]
1228
1367
  }
@@ -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 || 1.0.2 || 1.0.4 || 1.1.0 || 1.2.0 || 1.3.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 || 1.0.4 || 1.1.0 || 1.2.0 || 1.3.0 || 1.4.0'"
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 || 1.0.0 || 1.0.2 || 1.0.4 || 1.1.0 || 1.2.0'"
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 || 1.0.2 || 1.0.4 || 1.1.0 || 1.2.0 || 1.3.0'"
14
14
  ],
15
15
  "gate": ["bash", "run.sh", "check-dep-versions"],
16
16
  "timeoutSeconds": 300,
@@ -21,8 +21,8 @@
21
21
  "claim": "PI-SDK-PRODUCTION-SET",
22
22
  "title": "the durable library's production pin falls one release behind the SDK set the pin declares, so the carrier would bind a pi-durable nobody verified it against",
23
23
  "subject": "package.json",
24
- "find": ["\"@earendil-works/pi-durable\": \"1.3.0\","],
25
- "replace": ["\"@earendil-works/pi-durable\": \"1.2.0\","],
24
+ "find": ["\"@earendil-works/pi-durable\": \"1.4.0\","],
25
+ "replace": ["\"@earendil-works/pi-durable\": \"1.3.0\","],
26
26
  "gate": ["bash", "run.sh", "check-dep-versions"],
27
27
  "timeoutSeconds": 300,
28
28
  "signature": "[QK:PI-SDK-PRODUCTION-SET]",
@@ -33,7 +33,7 @@
33
33
  "title": "an @earendil-works package returns as a dev dependency beside its production pin, one name in two dependency classes",
34
34
  "subject": "package.json",
35
35
  "find": ["\"@biomejs/biome\": \"^2.4.13\","],
36
- "replace": ["\"@biomejs/biome\": \"^2.4.13\",\n\t\t\"@earendil-works/pi-ai\": \"1.3.0\","],
36
+ "replace": ["\"@biomejs/biome\": \"^2.4.13\",\n\t\t\"@earendil-works/pi-ai\": \"1.4.0\","],
37
37
  "gate": ["bash", "run.sh", "check-dep-versions"],
38
38
  "timeoutSeconds": 300,
39
39
  "signature": "[QK:PI-SDK-NO-DUAL-DECLARATION]",
@@ -0,0 +1,72 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "lane": "pi-retire-request",
4
+ "mutants": [
5
+ {
6
+ "claim": "PI-RETIRE-PREFLIGHT",
7
+ "title": "a mismatched native session escapes preflight and sends a retirement RPC",
8
+ "subject": "pi-extensions/lib/pi-retire-request.ts",
9
+ "find": ["\t\ttarget.nativeSessionId !== expected.nativeSessionId ||\n"],
10
+ "replace": [""],
11
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
12
+ "timeoutSeconds": 600,
13
+ "signature": "[QK:PI-RETIRE-PREFLIGHT]",
14
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
15
+ },
16
+ {
17
+ "claim": "PI-RETIRE-WIRE",
18
+ "title": "the one fixed retirement request carries a different native session than the certified record",
19
+ "subject": "pi-extensions/lib/pi-retire-request.ts",
20
+ "find": ["{ type: \"retire\", gardenId: target.gardenId, nativeSessionId: target.nativeSessionId }"],
21
+ "replace": ["{ type: \"retire\", gardenId: target.gardenId, nativeSessionId: \"wrong-native-id\" }"],
22
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
23
+ "timeoutSeconds": 600,
24
+ "signature": "[QK:PI-RETIRE-WIRE]",
25
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
26
+ },
27
+ {
28
+ "claim": "PI-RETIRE-PARSE-CLOSED",
29
+ "title": "a failure response with a requested boundary is incorrectly accepted",
30
+ "subject": "pi-extensions/lib/pi-retire-request.ts",
31
+ "find": ["if (response.success === true && data.boundary === \"shutdown-requested\") {"],
32
+ "replace": ["if (data.boundary === \"shutdown-requested\") {"],
33
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
34
+ "timeoutSeconds": 600,
35
+ "signature": "[QK:PI-RETIRE-PARSE-CLOSED]",
36
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
37
+ },
38
+ {
39
+ "claim": "PI-RETIRE-REFUSALS",
40
+ "title": "the known receiver refusal domain is dropped and every named refusal becomes unknown",
41
+ "subject": "pi-extensions/lib/pi-retire-request.ts",
42
+ "find": ["if (data.boundary === \"refused\" && RECEIVER_REFUSALS.includes(data.reason as ReceiverRefusal)) {"],
43
+ "replace": ["if (false) {"],
44
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
45
+ "timeoutSeconds": 600,
46
+ "signature": "[QK:PI-RETIRE-REFUSALS]",
47
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
48
+ },
49
+ {
50
+ "claim": "PI-RETIRE-TRANSPORT",
51
+ "title": "a timeout or lost response is misreported as a certain receiver refusal",
52
+ "subject": "pi-extensions/lib/pi-retire-request.ts",
53
+ "find": ["\t\treturn { boundary: \"unknown\", reason: \"transport-error\" };"],
54
+ "replace": ["\t\treturn { boundary: \"refused\", phase: \"receiver\", reason: \"target-closing\" };"],
55
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
56
+ "timeoutSeconds": 600,
57
+ "signature": "[QK:PI-RETIRE-TRANSPORT]",
58
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
59
+ },
60
+ {
61
+ "claim": "PI-RETIRE-ENVELOPE",
62
+ "title": "the production receiver drops its error reason so the strict adapter cannot interpret refusals",
63
+ "subject": "pi-extensions/lib/control-retire.ts",
64
+ "find": ["\t\t...(result.boundary !== \"shutdown-requested\" ? { error: result.reason } : {}),\n"],
65
+ "replace": [""],
66
+ "gate": ["bash", "run.sh", "check-pi-retire-request"],
67
+ "timeoutSeconds": 600,
68
+ "signature": "[QK:PI-RETIRE-ENVELOPE]",
69
+ "signatureSource": "pi-extensions/lib/pi-retire-request.test.ts"
70
+ }
71
+ ]
72
+ }
@@ -55,14 +55,8 @@
55
55
  "claim": "RESUME-ID-GATE-SSOT",
56
56
  "title": "the preserved leaf's header stops naming the gate that certifies it, so a consumer-zero identity module ships on prose again",
57
57
  "subject": "pi-extensions/lib/resume-launch-identity.ts",
58
- "find": [
59
- " * So this leaf is preserved deliberately, with no consumer in the shipped tree today.",
60
- " * `check-resume-launch-identity` holds its contract so the record-integrity rules below —"
61
- ],
62
- "replace": [
63
- " * So this leaf is preserved deliberately for the later visible lane.",
64
- " * The record-integrity rules below —"
65
- ],
58
+ "find": [" * `check-resume-launch-identity` holds the record-integrity rules below — the transcript header id"],
59
+ "replace": [" * the record-integrity rules below — the transcript header id"],
66
60
  "gate": ["bash", "run.sh", "check-resume-launch-identity"],
67
61
  "timeoutSeconds": 60,
68
62
  "signature": "[QK:RESUME-ID-GATE-SSOT]",
@@ -106,6 +100,39 @@
106
100
  "timeoutSeconds": 60,
107
101
  "signature": "[QK:RESUME-ID-ACP-EXACT-CURATION]",
108
102
  "signatureSource": "scripts/check-resume-launch-identity.ts"
103
+ },
104
+ {
105
+ "claim": "RESUME-ID-CC-RESOLVES",
106
+ "title": "a claude-code record falls back to the out-of-domain refusal, so the widened domain exists only in prose",
107
+ "subject": "pi-extensions/lib/resume-launch-identity.ts",
108
+ "find": ["\tif (record.backend === \"claude-code\") return resolveClaudeCodeLaunchIdentity(gardenId, record);"],
109
+ "replace": [""],
110
+ "gate": ["bash", "run.sh", "check-resume-launch-identity"],
111
+ "timeoutSeconds": 60,
112
+ "signature": "[QK:RESUME-ID-CC-RESOLVES]",
113
+ "signatureSource": "scripts/check-resume-launch-identity.ts"
114
+ },
115
+ {
116
+ "claim": "RESUME-ID-CC-SESSION-GRAMMAR",
117
+ "title": "a recorded Claude Code session id outside the UUID grammar reaches claude --resume, where a value like --dangerously-skip-permissions would be read as a flag",
118
+ "subject": "pi-extensions/lib/resume-launch-identity.ts",
119
+ "find": ["\tif (!CLAUDE_SESSION_ID.test(record.nativeSessionId)) {"],
120
+ "replace": ["\tif (false && !CLAUDE_SESSION_ID.test(record.nativeSessionId)) {"],
121
+ "gate": ["bash", "run.sh", "check-resume-launch-identity"],
122
+ "timeoutSeconds": 60,
123
+ "signature": "[QK:RESUME-ID-CC-SESSION-GRAMMAR]",
124
+ "signatureSource": "scripts/check-resume-launch-identity.ts"
125
+ },
126
+ {
127
+ "claim": "RESUME-ID-CC-TRANSCRIPT-PRESENT",
128
+ "title": "a Claude Code record whose transcript is gone still resolves, so the window opens on a session the vendor cannot find",
129
+ "subject": "pi-extensions/lib/resume-launch-identity.ts",
130
+ "find": ["\tif (!isFile) {"],
131
+ "replace": ["\tif (false && !isFile) {"],
132
+ "gate": ["bash", "run.sh", "check-resume-launch-identity"],
133
+ "timeoutSeconds": 60,
134
+ "signature": "[QK:RESUME-ID-CC-TRANSCRIPT-PRESENT]",
135
+ "signatureSource": "scripts/check-resume-launch-identity.ts"
109
136
  }
110
137
  ]
111
138
  }