@llblab/pi-actors 0.42.3 → 0.43.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 (279) hide show
  1. package/AGENTS.md +127 -175
  2. package/BACKLOG.md +189 -1
  3. package/CHANGELOG.md +183 -292
  4. package/README.md +115 -276
  5. package/dist/fixtures/protocol/control-endpoint.json +6 -0
  6. package/dist/fixtures/protocol/control-record.json +9 -0
  7. package/dist/fixtures/protocol/recipe-summary.json +4 -12
  8. package/dist/fixtures/protocol/trace-event.json +9 -0
  9. package/dist/index.js +1 -1
  10. package/dist/lib/async-runs.d.ts +15 -38
  11. package/dist/lib/async-runs.js +173 -111
  12. package/dist/lib/automatic-review-runtime.d.ts +1 -1
  13. package/dist/lib/automatic-review-runtime.js +5 -5
  14. package/dist/lib/command-templates.d.ts +2 -0
  15. package/dist/lib/command-templates.js +38 -4
  16. package/dist/lib/control-projection.d.ts +20 -0
  17. package/dist/lib/control-projection.js +66 -0
  18. package/dist/lib/control.d.ts +15 -0
  19. package/dist/lib/control.js +97 -0
  20. package/dist/lib/draft-sleep.js +3 -3
  21. package/dist/lib/execution-sessions.d.ts +17 -0
  22. package/dist/lib/execution-sessions.js +85 -0
  23. package/dist/lib/file-state.d.ts +2 -0
  24. package/dist/lib/file-state.js +114 -46
  25. package/dist/lib/inspector-actions.d.ts +2 -2
  26. package/dist/lib/inspector-actions.js +2 -2
  27. package/dist/lib/inspector-command.js +3 -3
  28. package/dist/lib/inspector-overlay.d.ts +54 -70
  29. package/dist/lib/inspector-overlay.js +576 -910
  30. package/dist/lib/inspector.d.ts +3 -71
  31. package/dist/lib/inspector.js +19 -665
  32. package/dist/lib/limits.d.ts +7 -3
  33. package/dist/lib/limits.js +7 -3
  34. package/dist/lib/observability.d.ts +16 -16
  35. package/dist/lib/observability.js +43 -82
  36. package/dist/lib/prompts.d.ts +1 -1
  37. package/dist/lib/prompts.js +3 -3
  38. package/dist/lib/recipe-control.d.ts +7 -0
  39. package/dist/lib/recipe-control.js +43 -0
  40. package/dist/lib/recipes-discovery.js +2 -0
  41. package/dist/lib/recipes-references.d.ts +1 -14
  42. package/dist/lib/recipes-references.js +6 -21
  43. package/dist/lib/review-control.d.ts +1 -1
  44. package/dist/lib/review-control.js +4 -5
  45. package/dist/lib/review-projection.js +1 -5
  46. package/dist/lib/run-ui-runtime.js +2 -2
  47. package/dist/lib/runs-control-delivery.d.ts +28 -0
  48. package/dist/lib/runs-control-delivery.js +150 -0
  49. package/dist/lib/runs-controls.d.ts +37 -0
  50. package/dist/lib/runs-controls.js +146 -0
  51. package/dist/lib/runs-retention.d.ts +7 -0
  52. package/dist/lib/runs-retention.js +27 -3
  53. package/dist/lib/runs-start.js +4 -2
  54. package/dist/lib/runs-status.js +11 -6
  55. package/dist/lib/runs-trace.d.ts +24 -0
  56. package/dist/lib/runs-trace.js +102 -0
  57. package/dist/lib/runtime-identity.d.ts +7 -0
  58. package/dist/lib/runtime-identity.js +35 -0
  59. package/dist/lib/runtime-notifier.d.ts +1 -1
  60. package/dist/lib/runtime-notifier.js +1 -1
  61. package/dist/lib/runtime-triage.d.ts +29 -0
  62. package/dist/lib/runtime-triage.js +76 -0
  63. package/dist/lib/tool-review-scheduler.js +7 -7
  64. package/dist/lib/tools-inspect.d.ts +3 -3
  65. package/dist/lib/tools-inspect.js +241 -707
  66. package/dist/lib/tools-local.js +2 -10
  67. package/dist/lib/tools-message.d.ts +6 -7
  68. package/dist/lib/tools-message.js +95 -396
  69. package/dist/lib/tools-response.d.ts +1 -5
  70. package/dist/lib/tools-response.js +5 -48
  71. package/dist/lib/tools-spawn.js +16 -28
  72. package/dist/lib/tools.d.ts +1 -1
  73. package/dist/lib/tools.js +2 -3
  74. package/dist/lib/trace-projection.d.ts +22 -0
  75. package/dist/lib/trace-projection.js +185 -0
  76. package/dist/recipes/draft-review.json +0 -10
  77. package/dist/recipes/lens-swarm.json +0 -14
  78. package/dist/recipes/music-player.json +10 -19
  79. package/dist/recipes/pipeline-architect-coordinator.json +0 -11
  80. package/dist/recipes/pipeline-artifact-bundle.json +1 -22
  81. package/dist/recipes/pipeline-artifact-report.json +1 -18
  82. package/dist/recipes/pipeline-artifact-write.json +1 -18
  83. package/dist/recipes/pipeline-async-run-ops.json +0 -12
  84. package/dist/recipes/pipeline-checkpoint-continuation.json +0 -14
  85. package/dist/recipes/pipeline-development-tasking.json +0 -12
  86. package/dist/recipes/pipeline-docs-maintenance.json +0 -12
  87. package/dist/recipes/pipeline-media-library.json +0 -12
  88. package/dist/recipes/pipeline-quorum-review.json +0 -12
  89. package/dist/recipes/pipeline-release-readiness.json +0 -12
  90. package/dist/recipes/pipeline-release-summary.json +0 -12
  91. package/dist/recipes/pipeline-repo-health.json +0 -12
  92. package/dist/recipes/pipeline-research-synthesis.json +0 -11
  93. package/dist/recipes/pipeline-review-readiness.json +0 -12
  94. package/dist/recipes/resource-locker.json +27 -0
  95. package/dist/recipes/subagent-artifact.json +0 -9
  96. package/dist/recipes/subagent-checkpoint.json +0 -10
  97. package/dist/recipes/subagent-conflict-report.json +0 -11
  98. package/dist/recipes/subagent-contradiction-map.json +0 -11
  99. package/dist/recipes/subagent-critic.json +0 -11
  100. package/dist/recipes/subagent-evidence-map.json +0 -11
  101. package/dist/recipes/subagent-followup.json +0 -10
  102. package/dist/recipes/subagent-judge.json +0 -11
  103. package/dist/recipes/subagent-merge.json +0 -11
  104. package/dist/recipes/subagent-normalize.json +0 -11
  105. package/dist/recipes/subagent-plan.json +0 -11
  106. package/dist/recipes/subagent-preflight.json +0 -11
  107. package/dist/recipes/subagent-prompt.json +0 -10
  108. package/dist/recipes/subagent-quorum.json +0 -10
  109. package/dist/recipes/subagent-review-coordinator.json +0 -14
  110. package/dist/recipes/subagent-review.json +0 -11
  111. package/dist/recipes/subagent-task-card.json +0 -11
  112. package/dist/recipes/subagent-tools.json +0 -10
  113. package/dist/recipes/subagent-verify.json +0 -11
  114. package/dist/recipes/subagents-prompts.json +0 -10
  115. package/dist/recipes/tool-review.json +0 -10
  116. package/dist/scripts/async-runner.mjs +25 -25
  117. package/dist/scripts/conformance.mjs +4 -2
  118. package/dist/scripts/locker.mjs +196 -69
  119. package/dist/scripts/music-player.mjs +162 -159
  120. package/dist/scripts/recipe-utils.mjs +6 -96
  121. package/dist/scripts/release-gates.mjs +91 -0
  122. package/dist/scripts/validate-recipe.mjs +8 -57
  123. package/dist/skills/actors/SKILL.md +57 -265
  124. package/dist/skills/swarm/SKILL.md +10 -34
  125. package/docs/0.43-baseline.md +39 -0
  126. package/docs/README.md +4 -6
  127. package/docs/actor-inspector.md +26 -64
  128. package/docs/async-runs.md +81 -328
  129. package/docs/command-templates.md +8 -118
  130. package/docs/recipe-library.md +55 -182
  131. package/docs/releasing.md +28 -0
  132. package/docs/template-recipes.md +76 -289
  133. package/docs/tool-registry.md +41 -161
  134. package/fixtures/protocol/control-endpoint.json +6 -0
  135. package/fixtures/protocol/control-record.json +9 -0
  136. package/fixtures/protocol/recipe-summary.json +4 -12
  137. package/fixtures/protocol/trace-event.json +9 -0
  138. package/index.ts +1 -1
  139. package/lib/async-runs.ts +218 -204
  140. package/lib/automatic-review-runtime.ts +7 -7
  141. package/lib/command-templates.ts +44 -4
  142. package/lib/control-projection.ts +105 -0
  143. package/lib/control.ts +117 -0
  144. package/lib/draft-sleep.ts +3 -3
  145. package/lib/execution-sessions.ts +111 -0
  146. package/lib/file-state.ts +84 -64
  147. package/lib/inspector-actions.ts +2 -2
  148. package/lib/inspector-command.ts +3 -3
  149. package/lib/inspector-overlay.ts +617 -1126
  150. package/lib/inspector.ts +46 -979
  151. package/lib/limits.ts +7 -3
  152. package/lib/observability.ts +60 -101
  153. package/lib/prompts.ts +3 -3
  154. package/lib/recipe-control.ts +52 -0
  155. package/lib/recipes-discovery.ts +2 -0
  156. package/lib/recipes-references.ts +9 -45
  157. package/lib/review-control.ts +4 -5
  158. package/lib/review-projection.ts +1 -5
  159. package/lib/run-ui-runtime.ts +2 -2
  160. package/lib/runs-control-delivery.ts +209 -0
  161. package/lib/runs-controls.ts +213 -0
  162. package/lib/runs-retention.ts +38 -3
  163. package/lib/runs-start.ts +4 -2
  164. package/lib/runs-status.ts +11 -6
  165. package/lib/runs-trace.ts +136 -0
  166. package/lib/runtime-identity.ts +39 -0
  167. package/lib/runtime-notifier.ts +1 -1
  168. package/lib/runtime-triage.ts +120 -0
  169. package/lib/tool-review-scheduler.ts +7 -7
  170. package/lib/tools-inspect.ts +283 -900
  171. package/lib/tools-local.ts +2 -12
  172. package/lib/tools-message.ts +112 -520
  173. package/lib/tools-response.ts +5 -64
  174. package/lib/tools-spawn.ts +16 -32
  175. package/lib/tools.ts +5 -6
  176. package/lib/trace-projection.ts +244 -0
  177. package/package.json +2 -1
  178. package/recipes/draft-review.json +0 -10
  179. package/recipes/lens-swarm.json +0 -14
  180. package/recipes/music-player.json +10 -19
  181. package/recipes/pipeline-architect-coordinator.json +0 -11
  182. package/recipes/pipeline-artifact-bundle.json +1 -22
  183. package/recipes/pipeline-artifact-report.json +1 -18
  184. package/recipes/pipeline-artifact-write.json +1 -18
  185. package/recipes/pipeline-async-run-ops.json +0 -12
  186. package/recipes/pipeline-checkpoint-continuation.json +0 -14
  187. package/recipes/pipeline-development-tasking.json +0 -12
  188. package/recipes/pipeline-docs-maintenance.json +0 -12
  189. package/recipes/pipeline-media-library.json +0 -12
  190. package/recipes/pipeline-quorum-review.json +0 -12
  191. package/recipes/pipeline-release-readiness.json +0 -12
  192. package/recipes/pipeline-release-summary.json +0 -12
  193. package/recipes/pipeline-repo-health.json +0 -12
  194. package/recipes/pipeline-research-synthesis.json +0 -11
  195. package/recipes/pipeline-review-readiness.json +0 -12
  196. package/recipes/resource-locker.json +27 -0
  197. package/recipes/subagent-artifact.json +0 -9
  198. package/recipes/subagent-checkpoint.json +0 -10
  199. package/recipes/subagent-conflict-report.json +0 -11
  200. package/recipes/subagent-contradiction-map.json +0 -11
  201. package/recipes/subagent-critic.json +0 -11
  202. package/recipes/subagent-evidence-map.json +0 -11
  203. package/recipes/subagent-followup.json +0 -10
  204. package/recipes/subagent-judge.json +0 -11
  205. package/recipes/subagent-merge.json +0 -11
  206. package/recipes/subagent-normalize.json +0 -11
  207. package/recipes/subagent-plan.json +0 -11
  208. package/recipes/subagent-preflight.json +0 -11
  209. package/recipes/subagent-prompt.json +0 -10
  210. package/recipes/subagent-quorum.json +0 -10
  211. package/recipes/subagent-review-coordinator.json +0 -14
  212. package/recipes/subagent-review.json +0 -11
  213. package/recipes/subagent-task-card.json +0 -11
  214. package/recipes/subagent-tools.json +0 -10
  215. package/recipes/subagent-verify.json +0 -11
  216. package/recipes/subagents-prompts.json +0 -10
  217. package/recipes/tool-review.json +0 -10
  218. package/scripts/async-runner.mjs +25 -25
  219. package/scripts/conformance.mjs +4 -2
  220. package/scripts/locker.mjs +196 -69
  221. package/scripts/music-player.mjs +162 -159
  222. package/scripts/recipe-utils.mjs +6 -96
  223. package/scripts/release-gates.mjs +91 -0
  224. package/scripts/validate-recipe.mjs +8 -57
  225. package/skills/actors/SKILL.md +57 -265
  226. package/skills/swarm/SKILL.md +10 -34
  227. package/dist/fixtures/protocol/actor-message-branch.json +0 -13
  228. package/dist/fixtures/protocol/mailbox-contract.json +0 -15
  229. package/dist/fixtures/protocol/room-message.json +0 -11
  230. package/dist/fixtures/protocol/room-roster.json +0 -11
  231. package/dist/fixtures/protocol/run-inbox-message.json +0 -9
  232. package/dist/fixtures/protocol/run-outbox-event.json +0 -9
  233. package/dist/lib/mailbox-loop.d.ts +0 -41
  234. package/dist/lib/mailbox-loop.js +0 -60
  235. package/dist/lib/messages.d.ts +0 -25
  236. package/dist/lib/messages.js +0 -122
  237. package/dist/lib/rooms.d.ts +0 -104
  238. package/dist/lib/rooms.js +0 -647
  239. package/dist/lib/runs-mailbox.d.ts +0 -25
  240. package/dist/lib/runs-mailbox.js +0 -146
  241. package/dist/lib/runs-messages.d.ts +0 -15
  242. package/dist/lib/runs-messages.js +0 -179
  243. package/dist/lib/runs-outbox.d.ts +0 -41
  244. package/dist/lib/runs-outbox.js +0 -87
  245. package/dist/lib/tools-mailbox.d.ts +0 -8
  246. package/dist/lib/tools-mailbox.js +0 -48
  247. package/dist/recipes/actor-worker.json +0 -39
  248. package/dist/recipes/coordinator-locker.json +0 -45
  249. package/dist/recipes/locker.json +0 -45
  250. package/dist/recipes/pipeline-room-swarm.json +0 -50
  251. package/dist/recipes/subagent-message.json +0 -32
  252. package/dist/recipes/utility-actor-message.json +0 -23
  253. package/dist/scripts/actor-worker.mjs +0 -214
  254. package/dist/scripts/coordinator.mjs +0 -799
  255. package/docs/actor-messages.md +0 -225
  256. package/docs/actors-deep-reference.md +0 -66
  257. package/docs/component-recipes.md +0 -148
  258. package/docs/task-first-recipes.md +0 -263
  259. package/fixtures/protocol/actor-message-branch.json +0 -13
  260. package/fixtures/protocol/mailbox-contract.json +0 -15
  261. package/fixtures/protocol/room-message.json +0 -11
  262. package/fixtures/protocol/room-roster.json +0 -11
  263. package/fixtures/protocol/run-inbox-message.json +0 -9
  264. package/fixtures/protocol/run-outbox-event.json +0 -9
  265. package/lib/mailbox-loop.ts +0 -144
  266. package/lib/messages.ts +0 -151
  267. package/lib/rooms.ts +0 -939
  268. package/lib/runs-mailbox.ts +0 -208
  269. package/lib/runs-messages.ts +0 -252
  270. package/lib/runs-outbox.ts +0 -144
  271. package/lib/tools-mailbox.ts +0 -56
  272. package/recipes/actor-worker.json +0 -39
  273. package/recipes/coordinator-locker.json +0 -45
  274. package/recipes/locker.json +0 -45
  275. package/recipes/pipeline-room-swarm.json +0 -50
  276. package/recipes/subagent-message.json +0 -32
  277. package/recipes/utility-actor-message.json +0 -23
  278. package/scripts/actor-worker.mjs +0 -214
  279. package/scripts/coordinator.mjs +0 -799
@@ -26,7 +26,6 @@ function usage() {
26
26
  recipe-utils.mjs changelog-section <file> <version>
27
27
  recipe-utils.mjs artifact-manifest <artifact-path> <title> <status> [summary]
28
28
  recipe-utils.mjs artifact-write <artifact-path> [create|overwrite|append]
29
- recipe-utils.mjs actor-message <type> [to] [from] [summary] [metadata-json] [correlation-id] [reply-to]
30
29
  recipe-utils.mjs package-summary <package-json>
31
30
  recipe-utils.mjs skill-summary <skill-md> [package-json]`);
32
31
  }
@@ -36,41 +35,6 @@ function fail(message) {
36
35
  process.exit(1);
37
36
  }
38
37
 
39
- const ADDRESS_PATTERN = /^[A-Za-z0-9_.-]+$/;
40
- const MESSAGE_TYPE_PATTERN = /^[A-Za-z][A-Za-z0-9_.:-]*$/;
41
- function assertToken(value, label) {
42
- const normalized = String(value ?? "").trim();
43
- if (!normalized) fail(`${label} is required`);
44
- if (!ADDRESS_PATTERN.test(normalized))
45
- fail(`${label} contains unsupported characters: ${value}`);
46
- return normalized;
47
- }
48
-
49
- function validateActorAddress(address, label) {
50
- const value = String(address ?? "").trim();
51
- if (value === "coordinator") return value;
52
- const separator = value.indexOf(":");
53
- if (separator < 0) fail(`${label} must include an actor kind: ${address}`);
54
- const kind = value.slice(0, separator);
55
- const rest = value.slice(separator + 1);
56
- if (kind === "branch") {
57
- const [run, branch, ...extra] = rest.split("/");
58
- if (extra.length > 0)
59
- fail(`${label} branch address has too many parts: ${address}`);
60
- return `branch:${assertToken(run, `${label} branch run`)}/${assertToken(branch, `${label} branch id`)}`;
61
- }
62
- if (["run", "session", "tool"].includes(kind))
63
- return `${kind}:${assertToken(rest, label)}`;
64
- fail(`${label} has unsupported actor kind: ${kind}`);
65
- }
66
-
67
- function validateMessageType(type) {
68
- const value = String(type ?? "").trim();
69
- if (!MESSAGE_TYPE_PATTERN.test(value))
70
- fail(`Invalid actor message type: ${type}`);
71
- return value;
72
- }
73
-
74
38
  function walkFiles(dir, maxDepth = 2, depth = 0, out = []) {
75
39
  if (depth > maxDepth || !existsSync(dir)) return out;
76
40
  for (const entry of readdirSync(dir)) {
@@ -172,7 +136,7 @@ function runOpsSnapshot(
172
136
  rootValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
173
137
  );
174
138
  const inspectedRun = String(runIdValue || "music");
175
- const messageFile = join(root, inspectedRun, "outbox.jsonl");
139
+ const traceFile = join(root, inspectedRun, "trace.jsonl");
176
140
  const staleMs = Number(staleMinutesValue) * 60 * 1000;
177
141
  const now = Date.now();
178
142
  const recommendations = runs.flatMap((run) => {
@@ -186,10 +150,9 @@ function runOpsSnapshot(
186
150
  {
187
151
  run: run.run,
188
152
  reason: "running-stale",
189
- suggested_message: {
190
- to: `run:${run.run}`,
191
- type: "control.stop",
192
- body: "stop",
153
+ suggested_inspect: {
154
+ target: `run:${run.run}`,
155
+ view: "control",
193
156
  },
194
157
  },
195
158
  ];
@@ -199,7 +162,7 @@ function runOpsSnapshot(
199
162
  {
200
163
  run: run.run,
201
164
  reason: `terminal-${run.status}`,
202
- suggested_inspect: { target: `run:${run.run}`, view: "tail" },
165
+ suggested_inspect: { target: `run:${run.run}`, view: "trace" },
203
166
  },
204
167
  ];
205
168
  }
@@ -210,7 +173,7 @@ function runOpsSnapshot(
210
173
  {
211
174
  runs,
212
175
  inspectedRun,
213
- messages: tailJsonl(messageFile, linesValue),
176
+ trace: tailJsonl(traceFile, linesValue),
214
177
  recommendations,
215
178
  },
216
179
  null,
@@ -291,57 +254,6 @@ function artifactWrite(pathValue, mode = "create") {
291
254
  );
292
255
  }
293
256
 
294
- function actorMessage(
295
- type = "event",
296
- to = "coordinator",
297
- from = "run:{run_id}",
298
- summary = "",
299
- metadataValue = "",
300
- correlationId = "",
301
- replyTo = "",
302
- ) {
303
- const messageType = validateMessageType(type);
304
- const messageTo = validateActorAddress(to, "message.to");
305
- const messageFrom = validateActorAddress(from, "message.from");
306
- let metadata = {};
307
- if (metadataValue) {
308
- try {
309
- const parsed = JSON.parse(metadataValue);
310
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
311
- metadata = parsed;
312
- else fail("Actor message metadata must be a JSON object");
313
- } catch (error) {
314
- fail(`Invalid actor message metadata JSON: ${error.message}`);
315
- }
316
- }
317
- const bodyText = readFileSync(0, "utf8");
318
- const trimmed = bodyText.trim();
319
- let body = bodyText;
320
- if (trimmed) {
321
- try {
322
- body = JSON.parse(trimmed);
323
- } catch {
324
- body = bodyText;
325
- }
326
- }
327
- console.log(
328
- JSON.stringify(
329
- {
330
- to: messageTo,
331
- from: messageFrom,
332
- type: messageType,
333
- summary: summary || messageType,
334
- body,
335
- ...(correlationId ? { correlation_id: correlationId } : {}),
336
- ...(replyTo ? { reply_to: replyTo } : {}),
337
- metadata,
338
- },
339
- null,
340
- 2,
341
- ),
342
- );
343
- }
344
-
345
257
  function packageSummary(fileValue = "package.json") {
346
258
  const file = resolve(
347
259
  fileValue.replace(/^~(?=\/|$)/, process.env.HOME ?? "~"),
@@ -475,8 +387,6 @@ else if (command === "artifact-manifest")
475
387
  artifactManifest(args[0] ?? "artifact.md", args[1], args[2], args[3]);
476
388
  else if (command === "artifact-write")
477
389
  artifactWrite(args[0] ?? "artifact.md", args[1] ?? "create");
478
- else if (command === "actor-message")
479
- actorMessage(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
480
390
  else if (command === "package-summary")
481
391
  packageSummary(args[0] ?? "package.json");
482
392
  else if (command === "skill-summary")
@@ -93,6 +93,97 @@ try {
93
93
  }
94
94
  console.log("[release] bounded secret and public-path hygiene checked");
95
95
 
96
+ const removedPaths = [
97
+ "lib/messages.ts",
98
+ "lib/rooms.ts",
99
+ "lib/mailbox-loop.ts",
100
+ "lib/runs-mailbox.ts",
101
+ "lib/runs-messages.ts",
102
+ "lib/runs-outbox.ts",
103
+ "lib/tools-mailbox.ts",
104
+ "scripts/actor-worker.mjs",
105
+ "scripts/coordinator.mjs",
106
+ "recipes/actor-worker.json",
107
+ "recipes/pipeline-room-swarm.json",
108
+ "recipes/subagent-message.json",
109
+ "recipes/utility-actor-message.json",
110
+ "docs/actor-messages.md",
111
+ "docs/run-inspector.md",
112
+ "lib/run-inspector.ts",
113
+ "lib/run-inspector-overlay.ts",
114
+ ];
115
+ for (const path of removedPaths) check(!fileSet.has(path), `removed surface returned: ${path}`);
116
+
117
+ const currentSurface = /^(?:lib\/|scripts\/|recipes\/|fixtures\/|skills\/|docs\/|README\.md|AGENTS\.md)/u;
118
+ const forbiddenPatterns = [
119
+ [/room:</u, "room address"],
120
+ [/branch:</u, "branch address"],
121
+ [/communication\.json/u, "communication snapshot"],
122
+ [/\bActor(?:Address|Message)\b/u, "legacy actor type"],
123
+ [/\b(?:actor_address|default_room)\b/u, "legacy spawn placeholder"],
124
+ [/inbox\.jsonl/u, "legacy inbox state"],
125
+ ];
126
+ for (const path of files.filter((candidate) => currentSurface.test(candidate))) {
127
+ if (path === "BACKLOG.md" || path === "CHANGELOG.md" || path === "scripts/release-gates.mjs") continue;
128
+ const text = stagedText(path) ?? "";
129
+ for (const [pattern, label] of forbiddenPatterns) {
130
+ check(!pattern.test(text), `${label} in current surface: ${path}`);
131
+ }
132
+ }
133
+ const legacyFallbacks = new Map([
134
+ ["lib/observability.ts", "outbox.jsonl"],
135
+ ["lib/runs-status.ts", "events.jsonl"],
136
+ ["lib/runs-start.ts", "events.jsonl"],
137
+ ]);
138
+ for (const path of files.filter((candidate) => currentSurface.test(candidate))) {
139
+ if (path === "BACKLOG.md" || path === "CHANGELOG.md" || path === "scripts/release-gates.mjs") continue;
140
+ const text = stagedText(path) ?? "";
141
+ for (const term of ["outbox.jsonl", "events.jsonl"]) {
142
+ if (!text.includes(term)) continue;
143
+ check(legacyFallbacks.get(path) === term, `legacy state reference outside read-only fallback: ${path} (${term})`);
144
+ }
145
+ }
146
+ console.log("[release] removed-surface and legacy-fallback allowlists checked");
147
+
148
+ const directTraceWrite = /(?:appendFileSync|writeFileSync|writeText(?:Atomic)?)\s*\(\s*[A-Za-z0-9_.]*?(?:trace|event)(?:Path|File)/iu;
149
+ for (const path of files.filter((candidate) =>
150
+ (candidate.startsWith("lib/") && candidate.endsWith(".ts")) ||
151
+ (candidate.startsWith("scripts/") && candidate.endsWith(".mjs"))
152
+ )) {
153
+ if (path === "lib/runs-trace.ts") continue;
154
+ check(!directTraceWrite.test(stagedText(path) ?? ""), `direct Trace writer outside canonical authority: ${path}`);
155
+ }
156
+ const canonicalTrace = stagedText("lib/runs-trace.ts") ?? "";
157
+ check(/withFileMutationLock\(path/u.test(canonicalTrace), "canonical Trace append lacks mutation lock");
158
+ for (const path of [
159
+ "scripts/async-runner.mjs",
160
+ "scripts/locker.mjs",
161
+ "scripts/music-player.mjs",
162
+ ]) {
163
+ const text = stagedText(path) ?? "";
164
+ check(
165
+ text.includes('importRuntimeModule("runs-trace")') && text.includes("appendRunTraceEvent"),
166
+ `first-party Trace writer bypasses canonical runtime module: ${path}`,
167
+ );
168
+ }
169
+ console.log("[release] canonical Trace writer residue checked");
170
+
171
+ check(
172
+ (stagedText("scripts/validate-recipe.mjs") ?? "").includes(
173
+ "qaReport.diagnostics.length === 0 && qaReport.warnings.length === 0",
174
+ ),
175
+ "Recipe QA warnings are not release-blocking",
176
+ );
177
+ console.log("[release] zero-warning Recipe QA gate checked");
178
+
179
+ const baselineShippedLines = 28_853;
180
+ const shippedPath = /^(?:lib\/|scripts\/|recipes\/|docs\/|skills\/)/u;
181
+ const shippedLines = files
182
+ .filter((path) => shippedPath.test(path))
183
+ .reduce((total, path) => total + (((stagedText(path) ?? "").match(/\n/gu) ?? []).length + 1), 0);
184
+ check(shippedLines < baselineShippedLines, `shipped lines ${shippedLines} are not below baseline ${baselineShippedLines}`);
185
+ console.log(`[release] shipped lines ${shippedLines} < released baseline ${baselineShippedLines}`);
186
+
96
187
  const sources = files.filter((path) => path === "index.ts" || (path.startsWith("lib/") && path.endsWith(".ts")));
97
188
  const sourceSet = new Set(sources);
98
189
  const graph = new Map();
@@ -29,7 +29,7 @@ export function validateRecipeUsage() {
29
29
  return `Usage:
30
30
  validate-recipe.mjs <recipe-file-or-dir> [--all] [--qa] [--summary]
31
31
 
32
- Validates one template recipe file, or all *.json/*.md files in a directory when --all is set. Add --qa for packaged-recipe quality checks. Add --summary for compact CLI output.`;
32
+ Validates one template recipe file, or all *.json/*.md files in a directory when --all is set. Add --qa for packaged-recipe quality checks, where diagnostics and warnings fail validation. Add --summary for compact CLI output.`;
33
33
  }
34
34
 
35
35
  function expandPath(value) {
@@ -63,13 +63,6 @@ function recipeFiles(target, all) {
63
63
  .map((file) => resolve(target, file));
64
64
  }
65
65
 
66
- function mailboxType(value) {
67
- if (typeof value === "string") return value;
68
- if (value && typeof value === "object" && typeof value.type === "string")
69
- return value.type;
70
- return undefined;
71
- }
72
-
73
66
  function collectTemplateStrings(value, out = []) {
74
67
  if (typeof value === "string") out.push(value);
75
68
  else if (Array.isArray(value)) value.forEach((item) => collectTemplateStrings(item, out));
@@ -124,46 +117,11 @@ function validateHelperPaths(file, config) {
124
117
  return diagnostics;
125
118
  }
126
119
 
127
- function validateMailboxContract(file, config) {
128
- const diagnostics = [];
129
- const mailbox = config.mailbox;
130
- const accepts = Array.isArray(mailbox?.accepts) ? mailbox.accepts : [];
131
- const emits = Array.isArray(mailbox?.emits) ? mailbox.emits : [];
132
- if (config.async === true && !mailbox)
133
- diagnostics.push("mailbox: async recipes must declare mailbox metadata");
134
- if (config.async === true && !accepts.map(mailboxType).includes("control.kill"))
135
- diagnostics.push("mailbox.accepts: async recipes must include control.kill");
136
- const allowedLegacyTypes = new Set(["awaiting_assignment"]);
137
- for (const [key, entries] of Object.entries({ accepts, emits })) {
138
- entries.forEach((entry, index) => {
139
- const type = mailboxType(entry);
140
- if (!type) diagnostics.push(`mailbox.${key}[${index}]: must be a string or object with type`);
141
- else if (
142
- !allowedLegacyTypes.has(type) &&
143
- !/^[a-z][a-z0-9_-]*\.(?:[a-z][a-z0-9_-]*|\*)$/.test(type)
144
- )
145
- diagnostics.push(`mailbox.${key}[${index}]: message type must use channel.action form`);
146
- });
147
- }
148
- const allowedDomainTermination = new Set([
149
- "coordinator-locker.json",
150
- "locker.json",
151
- "music-player.json",
152
- ]);
153
- const hasDomainTermination = accepts
154
- .map(mailboxType)
155
- .some((type) => type === "control.stop" || type === "control.cancel");
156
- if (hasDomainTermination && !allowedDomainTermination.has(file.split(/[\\/]/).pop()))
157
- diagnostics.push("mailbox.accepts: control.stop/control.cancel are reserved for actor-domain handlers");
158
- return diagnostics;
159
- }
160
-
161
120
  function qaDiagnostics(file, config) {
162
121
  const diagnostics = [];
163
122
  const warnings = [];
164
- if (typeof config.description !== "string" || !config.description.trim())
165
- warnings.push("description: missing or empty");
166
- diagnostics.push(...validateMailboxContract(file, config));
123
+ if (config.mailbox !== undefined)
124
+ diagnostics.push("recipe.mailbox was removed; use control actions and Trace events");
167
125
  diagnostics.push(...validateArtifactDeclarations(config));
168
126
  diagnostics.push(...validateHelperPaths(file, config));
169
127
  const platformSpecificTemplate = collectTemplateStrings(config.template).some(
@@ -178,7 +136,7 @@ function qaDiagnostics(file, config) {
178
136
  }
179
137
 
180
138
  function qaOk(qaReport) {
181
- return qaReport.diagnostics.length === 0;
139
+ return qaReport.diagnostics.length === 0 && qaReport.warnings.length === 0;
182
140
  }
183
141
 
184
142
  function validateFile(file, qa = false) {
@@ -201,17 +159,7 @@ function validateFile(file, qa = false) {
201
159
  config.imports && typeof config.imports === "object"
202
160
  ? Object.keys(config.imports).sort()
203
161
  : [],
204
- mailbox:
205
- config.mailbox && typeof config.mailbox === "object"
206
- ? {
207
- accepts: Array.isArray(config.mailbox.accepts)
208
- ? config.mailbox.accepts
209
- : [],
210
- emits: Array.isArray(config.mailbox.emits)
211
- ? config.mailbox.emits
212
- : [],
213
- }
214
- : undefined,
162
+ control: Array.isArray(config.control) ? config.control : undefined,
215
163
  ...(qa
216
164
  ? {
217
165
  qa: {
@@ -275,6 +223,9 @@ function summarizeReport(report) {
275
223
  ...(result.qa?.diagnostics?.length
276
224
  ? { diagnostics: result.qa.diagnostics }
277
225
  : {}),
226
+ ...(result.qa?.warnings?.length
227
+ ? { warnings: result.qa.warnings }
228
+ : {}),
278
229
  })),
279
230
  };
280
231
  }