@mastra/factory 0.24.0-alpha.8 → 0.24.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 (301) hide show
  1. package/README.md +4 -4
  2. package/dist/environment/build-runner.js +2 -1
  3. package/dist/environment/build-runner.js.map +1 -1
  4. package/dist/environment/build-workflow.js +1 -1
  5. package/dist/environment/build-workflow.js.map +1 -1
  6. package/dist/environment/build.js +16 -14
  7. package/dist/environment/build.js.map +1 -1
  8. package/dist/factory.d.ts.map +1 -1
  9. package/dist/factory.js +111 -19
  10. package/dist/factory.js.map +1 -1
  11. package/dist/integrations/base.d.ts +1 -1
  12. package/dist/integrations/base.d.ts.map +1 -1
  13. package/dist/integrations/github/app-identity.js.map +1 -1
  14. package/dist/integrations/github/integration.js +1 -1
  15. package/dist/integrations/github/integration.js.map +1 -1
  16. package/dist/integrations/github/reconcile-worker.js +1 -1
  17. package/dist/integrations/github/reconcile-worker.js.map +1 -1
  18. package/dist/integrations/github/routes.d.ts +1 -1
  19. package/dist/integrations/github/routes.d.ts.map +1 -1
  20. package/dist/integrations/github/routes.js +24 -13
  21. package/dist/integrations/github/routes.js.map +1 -1
  22. package/dist/integrations/github/rules.d.ts.map +1 -1
  23. package/dist/integrations/github/rules.js +53 -9
  24. package/dist/integrations/github/rules.js.map +1 -1
  25. package/dist/integrations/github/sandbox.js +2 -2
  26. package/dist/integrations/github/sandbox.js.map +1 -1
  27. package/dist/integrations/github/session-subscriptions.d.ts.map +1 -1
  28. package/dist/integrations/github/session-subscriptions.js +1 -2
  29. package/dist/integrations/github/session-subscriptions.js.map +1 -1
  30. package/dist/integrations/github/subscriptions.d.ts +7 -4
  31. package/dist/integrations/github/subscriptions.d.ts.map +1 -1
  32. package/dist/integrations/github/subscriptions.js +5 -5
  33. package/dist/integrations/github/subscriptions.js.map +1 -1
  34. package/dist/integrations/gitlab/api.js.map +1 -1
  35. package/dist/integrations/gitlab/integration.js.map +1 -1
  36. package/dist/integrations/gitlab/reconciliation-config.js +2 -1
  37. package/dist/integrations/gitlab/reconciliation-config.js.map +1 -1
  38. package/dist/integrations/gitlab/routes.d.ts.map +1 -1
  39. package/dist/integrations/gitlab/routes.js +10 -6
  40. package/dist/integrations/gitlab/routes.js.map +1 -1
  41. package/dist/integrations/gitlab/rules.js.map +1 -1
  42. package/dist/integrations/gitlab/session-subscriptions.d.ts.map +1 -1
  43. package/dist/integrations/gitlab/session-subscriptions.js +1 -2
  44. package/dist/integrations/gitlab/session-subscriptions.js.map +1 -1
  45. package/dist/integrations/gitlab/subscriptions.d.ts +7 -4
  46. package/dist/integrations/gitlab/subscriptions.d.ts.map +1 -1
  47. package/dist/integrations/gitlab/subscriptions.js +5 -5
  48. package/dist/integrations/gitlab/subscriptions.js.map +1 -1
  49. package/dist/integrations/incidentio/api.js.map +1 -1
  50. package/dist/integrations/incidentio/integration.js.map +1 -1
  51. package/dist/integrations/incidentio/rules.js.map +1 -1
  52. package/dist/integrations/issue-reconcile-worker.js +1 -1
  53. package/dist/integrations/issue-reconcile-worker.js.map +1 -1
  54. package/dist/integrations/issue-reconciler.js +1 -1
  55. package/dist/integrations/issue-reconciler.js.map +1 -1
  56. package/dist/integrations/jira/api.js.map +1 -1
  57. package/dist/integrations/jira/integration.js.map +1 -1
  58. package/dist/integrations/jira/rules.js.map +1 -1
  59. package/dist/integrations/linear/agent-tools.d.ts.map +1 -1
  60. package/dist/integrations/linear/agent-tools.js.map +1 -1
  61. package/dist/integrations/linear/integration.js.map +1 -1
  62. package/dist/integrations/linear/rules.js.map +1 -1
  63. package/dist/integrations/platform/api-client.js.map +1 -1
  64. package/dist/integrations/platform/github/event-worker.js +1 -1
  65. package/dist/integrations/platform/github/event-worker.js.map +1 -1
  66. package/dist/integrations/platform/github/integration.js +2 -2
  67. package/dist/integrations/platform/github/integration.js.map +1 -1
  68. package/dist/integrations/platform/gitlab/event-worker.js.map +1 -1
  69. package/dist/integrations/platform/gitlab/integration.js.map +1 -1
  70. package/dist/integrations/platform/incidentio/integration.js +2 -1
  71. package/dist/integrations/platform/incidentio/integration.js.map +1 -1
  72. package/dist/integrations/platform/jira/integration.js.map +1 -1
  73. package/dist/integrations/platform/linear/event-worker.js +1 -1
  74. package/dist/integrations/platform/linear/event-worker.js.map +1 -1
  75. package/dist/integrations/platform/linear/integration.js.map +1 -1
  76. package/dist/integrations/slack/connect-route.js +1 -1
  77. package/dist/integrations/slack/connect-route.js.map +1 -1
  78. package/dist/integrations/slack/feed-publisher.js +1 -1
  79. package/dist/integrations/slack/feed-publisher.js.map +1 -1
  80. package/dist/integrations/slack/integration.js +1 -1
  81. package/dist/integrations/slack/integration.js.map +1 -1
  82. package/dist/integrations/slack/slack.d.ts +16 -5
  83. package/dist/integrations/slack/slack.d.ts.map +1 -1
  84. package/dist/integrations/slack/slack.js +87 -34
  85. package/dist/integrations/slack/slack.js.map +1 -1
  86. package/dist/integrations/subscription-session.d.ts +0 -1
  87. package/dist/integrations/subscription-session.d.ts.map +1 -1
  88. package/dist/integrations/subscription-session.js +1 -4
  89. package/dist/integrations/subscription-session.js.map +1 -1
  90. package/dist/integrations/workos/integration.js.map +1 -1
  91. package/dist/mcp/routes.d.ts.map +1 -1
  92. package/dist/mcp/routes.js +1 -1
  93. package/dist/mcp/routes.js.map +1 -1
  94. package/dist/packages/_internals/workspace/dist/index.js +18 -1
  95. package/dist/packages/_internals/workspace/dist/index.js.map +1 -1
  96. package/dist/routes/attention-activity.d.ts.map +1 -1
  97. package/dist/routes/attention-activity.js +5 -2
  98. package/dist/routes/attention-activity.js.map +1 -1
  99. package/dist/routes/attention-parked.js.map +1 -1
  100. package/dist/routes/attention-providers.d.ts +0 -1
  101. package/dist/routes/attention-providers.d.ts.map +1 -1
  102. package/dist/routes/attention-providers.js +5 -6
  103. package/dist/routes/attention-providers.js.map +1 -1
  104. package/dist/routes/automation-runs.js.map +1 -1
  105. package/dist/routes/config.d.ts +6 -7
  106. package/dist/routes/config.d.ts.map +1 -1
  107. package/dist/routes/config.js +20 -19
  108. package/dist/routes/config.js.map +1 -1
  109. package/dist/routes/contracts.js +1 -1
  110. package/dist/routes/contracts.js.map +1 -1
  111. package/dist/routes/custom-provider-source.js.map +1 -1
  112. package/dist/routes/fs.d.ts +31 -23
  113. package/dist/routes/fs.d.ts.map +1 -1
  114. package/dist/routes/fs.js +218 -64
  115. package/dist/routes/fs.js.map +1 -1
  116. package/dist/routes/intake.js +2 -1
  117. package/dist/routes/intake.js.map +1 -1
  118. package/dist/routes/knowledge.js +1 -1
  119. package/dist/routes/knowledge.js.map +1 -1
  120. package/dist/routes/oauth.js +3 -2
  121. package/dist/routes/oauth.js.map +1 -1
  122. package/dist/routes/projects.d.ts +1 -1
  123. package/dist/routes/projects.d.ts.map +1 -1
  124. package/dist/routes/projects.js +33 -31
  125. package/dist/routes/projects.js.map +1 -1
  126. package/dist/routes/provider-credentials.d.ts.map +1 -1
  127. package/dist/routes/provider-credentials.js +6 -1
  128. package/dist/routes/provider-credentials.js.map +1 -1
  129. package/dist/routes/session-access.d.ts +55 -0
  130. package/dist/routes/session-access.d.ts.map +1 -0
  131. package/dist/routes/session-access.js +165 -0
  132. package/dist/routes/session-access.js.map +1 -0
  133. package/dist/routes/skills.d.ts +2 -4
  134. package/dist/routes/skills.d.ts.map +1 -1
  135. package/dist/routes/skills.js +19 -65
  136. package/dist/routes/skills.js.map +1 -1
  137. package/dist/routes/source-control-sessions.d.ts +6 -1
  138. package/dist/routes/source-control-sessions.d.ts.map +1 -1
  139. package/dist/routes/source-control-sessions.js +95 -12
  140. package/dist/routes/source-control-sessions.js.map +1 -1
  141. package/dist/routes/surface.d.ts +5 -0
  142. package/dist/routes/surface.d.ts.map +1 -1
  143. package/dist/routes/surface.js +10 -4
  144. package/dist/routes/surface.js.map +1 -1
  145. package/dist/routes/tenant-credentials.js.map +1 -1
  146. package/dist/routes/work-items.js.map +1 -1
  147. package/dist/rules/binding-context.js +11 -9
  148. package/dist/rules/binding-context.js.map +1 -1
  149. package/dist/rules/dispatcher.d.ts +1 -1
  150. package/dist/rules/dispatcher.d.ts.map +1 -1
  151. package/dist/rules/dispatcher.js +10 -10
  152. package/dist/rules/dispatcher.js.map +1 -1
  153. package/dist/rules/start-coordinator.d.ts +4 -0
  154. package/dist/rules/start-coordinator.d.ts.map +1 -1
  155. package/dist/rules/start-coordinator.js +36 -4
  156. package/dist/rules/start-coordinator.js.map +1 -1
  157. package/dist/rules/tools.js +2 -2
  158. package/dist/rules/tools.js.map +1 -1
  159. package/dist/rules/transition-service.js.map +1 -1
  160. package/dist/sandbox/callback-factory-sandbox.js.map +1 -1
  161. package/dist/sandbox/local-factory-sandbox.js.map +1 -1
  162. package/dist/sandbox/session-retirement.js.map +1 -1
  163. package/dist/secret-encryption.d.ts.map +1 -1
  164. package/dist/secret-encryption.js +65 -25
  165. package/dist/secret-encryption.js.map +1 -1
  166. package/dist/session/channel-reply-processor.d.ts +7 -6
  167. package/dist/session/channel-reply-processor.d.ts.map +1 -1
  168. package/dist/session/channel-reply-processor.js +9 -9
  169. package/dist/session/channel-reply-processor.js.map +1 -1
  170. package/dist/session/channel-session-link-processor.js +1 -0
  171. package/dist/session/channel-session-link-processor.js.map +1 -1
  172. package/dist/session/credential-policy.d.ts.map +1 -1
  173. package/dist/session/credential-policy.js +7 -6
  174. package/dist/session/credential-policy.js.map +1 -1
  175. package/dist/session/default-model-hydration.d.ts +1 -0
  176. package/dist/session/default-model-hydration.d.ts.map +1 -1
  177. package/dist/session/default-model-hydration.js +3 -2
  178. package/dist/session/default-model-hydration.js.map +1 -1
  179. package/dist/session/environment-state-processor.js +1 -1
  180. package/dist/session/environment-state-processor.js.map +1 -1
  181. package/dist/session/filesystem-capture.d.ts +3 -3
  182. package/dist/session/filesystem-capture.d.ts.map +1 -1
  183. package/dist/session/filesystem-capture.js +16 -17
  184. package/dist/session/filesystem-capture.js.map +1 -1
  185. package/dist/session/first-exec-capture.d.ts +1 -1
  186. package/dist/session/first-exec-capture.d.ts.map +1 -1
  187. package/dist/session/first-exec-capture.js +1 -1
  188. package/dist/session/first-exec-capture.js.map +1 -1
  189. package/dist/session/first-message-capture.d.ts +1 -1
  190. package/dist/session/first-message-capture.d.ts.map +1 -1
  191. package/dist/session/first-message-capture.js +1 -1
  192. package/dist/session/first-message-capture.js.map +1 -1
  193. package/dist/session/live-sessions.d.ts +1 -1
  194. package/dist/session/live-sessions.js +1 -1
  195. package/dist/session/live-sessions.js.map +1 -1
  196. package/dist/session/memory-settings-hydration.d.ts +1 -1
  197. package/dist/session/memory-settings-hydration.d.ts.map +1 -1
  198. package/dist/session/memory-settings-hydration.js +2 -1
  199. package/dist/session/memory-settings-hydration.js.map +1 -1
  200. package/dist/session/resource-migration.d.ts +105 -0
  201. package/dist/session/resource-migration.d.ts.map +1 -0
  202. package/dist/session/resource-migration.js +195 -0
  203. package/dist/session/resource-migration.js.map +1 -0
  204. package/dist/session/session-threads.d.ts +58 -0
  205. package/dist/session/session-threads.d.ts.map +1 -0
  206. package/dist/session/session-threads.js +90 -0
  207. package/dist/session/session-threads.js.map +1 -0
  208. package/dist/session/source-control-tools.js +8 -8
  209. package/dist/session/source-control-tools.js.map +1 -1
  210. package/dist/session/thinking-default.d.ts.map +1 -1
  211. package/dist/session/thinking-default.js +3 -4
  212. package/dist/session/thinking-default.js.map +1 -1
  213. package/dist/session/thread-session-stamp.d.ts +21 -0
  214. package/dist/session/thread-session-stamp.d.ts.map +1 -0
  215. package/dist/session/thread-session-stamp.js +20 -0
  216. package/dist/session/thread-session-stamp.js.map +1 -0
  217. package/dist/session/thread-title-mirror.d.ts +1 -1
  218. package/dist/session/thread-title-mirror.d.ts.map +1 -1
  219. package/dist/session/thread-title-mirror.js +1 -1
  220. package/dist/session/thread-title-mirror.js.map +1 -1
  221. package/dist/skills/service.d.ts +6 -8
  222. package/dist/skills/service.d.ts.map +1 -1
  223. package/dist/skills/service.js +3 -3
  224. package/dist/skills/service.js.map +1 -1
  225. package/dist/spa-static.js.map +1 -1
  226. package/dist/state-signing.js +1 -1
  227. package/dist/state-signing.js.map +1 -1
  228. package/dist/storage/domains/audit/agent-audit.d.ts.map +1 -1
  229. package/dist/storage/domains/audit/agent-audit.js +2 -2
  230. package/dist/storage/domains/audit/agent-audit.js.map +1 -1
  231. package/dist/storage/domains/audit/base.js.map +1 -1
  232. package/dist/storage/domains/audit/domain.js.map +1 -1
  233. package/dist/storage/domains/channel-identity/base.js.map +1 -1
  234. package/dist/storage/domains/comments/base.js.map +1 -1
  235. package/dist/storage/domains/comments/domain.js.map +1 -1
  236. package/dist/storage/domains/comments/feed-context.js.map +1 -1
  237. package/dist/storage/domains/credentials/base.js.map +1 -1
  238. package/dist/storage/domains/custom-providers/base.js.map +1 -1
  239. package/dist/storage/domains/intake/base.js.map +1 -1
  240. package/dist/storage/domains/integrations/base.d.ts +8 -0
  241. package/dist/storage/domains/integrations/base.d.ts.map +1 -1
  242. package/dist/storage/domains/integrations/base.js +7 -0
  243. package/dist/storage/domains/integrations/base.js.map +1 -1
  244. package/dist/storage/domains/memory-settings/base.js.map +1 -1
  245. package/dist/storage/domains/model-defaults/base.js.map +1 -1
  246. package/dist/storage/domains/projects/base.js.map +1 -1
  247. package/dist/storage/domains/queue-health/base.js.map +1 -1
  248. package/dist/storage/domains/source-control/base.d.ts +19 -0
  249. package/dist/storage/domains/source-control/base.d.ts.map +1 -1
  250. package/dist/storage/domains/source-control/base.js +42 -0
  251. package/dist/storage/domains/source-control/base.js.map +1 -1
  252. package/dist/storage/domains/source-control/inmemory.d.ts +5 -1
  253. package/dist/storage/domains/source-control/inmemory.d.ts.map +1 -1
  254. package/dist/storage/domains/source-control/inmemory.js +7 -0
  255. package/dist/storage/domains/source-control/inmemory.js.map +1 -1
  256. package/dist/storage/domains/work-items/base.d.ts +14 -0
  257. package/dist/storage/domains/work-items/base.d.ts.map +1 -1
  258. package/dist/storage/domains/work-items/base.js +25 -1
  259. package/dist/storage/domains/work-items/base.js.map +1 -1
  260. package/dist/storage/domains/work-items/board-version.js.map +1 -1
  261. package/dist/storage/domains/work-items/metrics.js.map +1 -1
  262. package/dist/tools/approval-tools.js +1 -1
  263. package/dist/tools/approval-tools.js.map +1 -1
  264. package/dist/tools/deliver.d.ts +8 -5
  265. package/dist/tools/deliver.d.ts.map +1 -1
  266. package/dist/tools/deliver.js +22 -8
  267. package/dist/tools/deliver.js.map +1 -1
  268. package/dist/tools/messaging-tools.d.ts +1 -1
  269. package/dist/tools/messaging-tools.d.ts.map +1 -1
  270. package/dist/tools/messaging-tools.js +203 -72
  271. package/dist/tools/messaging-tools.js.map +1 -1
  272. package/dist/tools/permissions.d.ts +1 -1
  273. package/dist/tools/permissions.d.ts.map +1 -1
  274. package/dist/tools/permissions.js +1 -1
  275. package/dist/tools/permissions.js.map +1 -1
  276. package/dist/tools/reports.d.ts.map +1 -1
  277. package/dist/tools/reports.js +10 -3
  278. package/dist/tools/reports.js.map +1 -1
  279. package/dist/tools/run-watch.d.ts +2 -0
  280. package/dist/tools/run-watch.d.ts.map +1 -1
  281. package/dist/tools/run-watch.js +42 -2
  282. package/dist/tools/run-watch.js.map +1 -1
  283. package/dist/tools/scope.d.ts +2 -1
  284. package/dist/tools/scope.d.ts.map +1 -1
  285. package/dist/tools/scope.js +3 -2
  286. package/dist/tools/scope.js.map +1 -1
  287. package/dist/tools/session-tools.d.ts +1 -1
  288. package/dist/tools/session-tools.d.ts.map +1 -1
  289. package/dist/tools/session-tools.js +33 -16
  290. package/dist/tools/session-tools.js.map +1 -1
  291. package/dist/tools/sessions-state-processor.js +2 -2
  292. package/dist/tools/sessions-state-processor.js.map +1 -1
  293. package/dist/tools/side-sessions.d.ts +1 -1
  294. package/dist/tools/side-sessions.d.ts.map +1 -1
  295. package/dist/tools/side-sessions.js +1 -1
  296. package/dist/tools/side-sessions.js.map +1 -1
  297. package/dist/workspace.d.ts +5 -2
  298. package/dist/workspace.d.ts.map +1 -1
  299. package/dist/workspace.js +28 -15
  300. package/dist/workspace.js.map +1 -1
  301. package/package.json +13 -13
@@ -166,10 +166,6 @@ function pullRequestProvenance(data, factoryProjectId) {
166
166
  }
167
167
  /** Identity under which label-driven relocations are recorded. */
168
168
  const LABEL_ROUTE_USER_ID = "factory-rule-dispatcher";
169
- function issueLabelChange(parsed) {
170
- const action = string(parsed.payload.action);
171
- return parsed.event === "issues" && (action === "labeled" || action === "unlabeled");
172
- }
173
169
  /**
174
170
  * Whether a login is Factory itself. Prefers the resolved identity, which is
175
171
  * observed from Factory's own writes, and falls back to the configured slug.
@@ -210,11 +206,12 @@ var GithubRules = class {
210
206
  if (!intake) return void 0;
211
207
  const { orgId, factoryProjectId } = project;
212
208
  if (labels.length > 0) {
213
- const route = resolveIntakeLabelRoute(await intake.listLabelRoutes({
209
+ const routes = await intake.listLabelRoutes({
214
210
  orgId,
215
211
  factoryProjectId,
216
212
  integrationId: "github"
217
- }), labels);
213
+ });
214
+ const route = resolveIntakeLabelRoute(routes, labels);
218
215
  const board = route ? this.options.boards.get(route.board) : void 0;
219
216
  if (board) return {
220
217
  board: board.id,
@@ -277,9 +274,53 @@ var GithubRules = class {
277
274
  });
278
275
  return { status: changed || outcome === "moved" ? "committed" : "ignored" };
279
276
  }
277
+ /**
278
+ * `assigned` / `unassigned` are not rule events either: an existing issue card only mirrors the
279
+ * issue's full assignee list. No card is created, moved, or handed to a run.
280
+ */
281
+ async #syncIssueAssignees(parsed, repositoryId, repositoryName, project) {
282
+ const issue = object(parsed.payload.issue);
283
+ const issueNumber = issue?.pull_request === void 0 ? number(issue?.number) : void 0;
284
+ if (!issueNumber) return { status: "ignored" };
285
+ const item = await this.#relatedItem(project.orgId, project.factoryProjectId, repositoryId, repositoryName, issueNumber, void 0, void 0, null);
286
+ if (!item || item.externalSource?.type !== "issue") return { status: "ignored" };
287
+ const assignees = actorLogins(issue?.assignees);
288
+ const updatedAt = string(issue?.updated_at);
289
+ const payloadTime = timestamp(updatedAt);
290
+ const storedTime = timestamp(item.metadata?.githubAssigneesUpdatedAt);
291
+ if (payloadTime !== void 0 && storedTime !== void 0 && payloadTime < storedTime) return { status: "ignored" };
292
+ const advancesTime = payloadTime !== void 0 && (storedTime === void 0 || payloadTime > storedTime);
293
+ if (sameStrings(item.metadata?.assignees, assignees) && !advancesTime) return { status: "ignored" };
294
+ try {
295
+ return { status: await this.options.storage.update({
296
+ orgId: item.orgId,
297
+ id: item.id,
298
+ userId: LABEL_ROUTE_USER_ID,
299
+ patch: { metadata: {
300
+ ...item.metadata ?? {},
301
+ assignees,
302
+ ...payloadTime !== void 0 ? { githubAssigneesUpdatedAt: updatedAt } : {}
303
+ } },
304
+ expectedRevision: item.revision
305
+ }) ? "committed" : "ignored" };
306
+ } catch (error) {
307
+ if (!(error instanceof WorkItemUpdateConflictError)) throw error;
308
+ return { status: "ignored" };
309
+ }
310
+ }
311
+ /** `issues` actions that are not rule events but still update an existing card. */
312
+ #issueActionHandler(parsed) {
313
+ if (parsed.event !== "issues") return void 0;
314
+ switch (string(parsed.payload.action)) {
315
+ case "labeled":
316
+ case "unlabeled": return (...args) => this.#relocateLabeledIssue(...args);
317
+ case "assigned":
318
+ case "unassigned": return (...args) => this.#syncIssueAssignees(...args);
319
+ default: return;
320
+ }
321
+ }
280
322
  async ingest(parsed) {
281
323
  const event = eventName(parsed);
282
- const labelChange = issueLabelChange(parsed);
283
324
  const repository = object(parsed.payload.repository);
284
325
  const installationId = number(object(parsed.payload.installation)?.id);
285
326
  const repositoryId = number(repository?.id);
@@ -289,14 +330,17 @@ var GithubRules = class {
289
330
  await this.#handOffPush(parsed, installationId, repositoryId);
290
331
  return { status: "ignored" };
291
332
  }
292
- if (!event && !labelChange || !installationId || !repositoryId || !repositoryName || !login) return { status: "ignored" };
333
+ if (!installationId || !repositoryId || !repositoryName || !login) return { status: "ignored" };
334
+ const issueAction = this.#issueActionHandler(parsed);
335
+ const handle = event ? (project) => this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project) : issueAction ? (project) => issueAction(parsed, repositoryId, repositoryName, project) : void 0;
336
+ if (!handle) return { status: "ignored" };
293
337
  const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({
294
338
  installationExternalId: String(installationId),
295
339
  repositoryExternalId: String(repositoryId)
296
340
  });
297
341
  if (projects.length === 0) return { status: "ignored" };
298
342
  const results = [];
299
- for (const project of projects) results.push(event ? await this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project) : await this.#relocateLabeledIssue(parsed, repositoryId, repositoryName, project));
343
+ for (const project of projects) results.push(await handle(project));
300
344
  if (results.some((result) => result.status === "committed")) return { status: "committed" };
301
345
  if (results.some((result) => result.status === "replayed")) return { status: "replayed" };
302
346
  return results[0] ?? { status: "ignored" };
@@ -1 +1 @@
1
- {"version":3,"file":"rules.js","names":["#intakeTarget","#relocateLabeledIssue","#relatedItem","#handOffPush","#ingestProject","#factoryMentionTarget","#isFactoryLogin","#linkedClosureItem","#resolveItem"],"sources":["../../../src/integrations/github/rules.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport {\n boardEventHandlers,\n boardForWorkItem,\n eventBoardId,\n rulePhaseField,\n withBoardClosure,\n workItemPhaseSemantics,\n} from '../../boards/index.js';\nimport type { BoardRegistry } from '../../boards/index.js';\nimport { cardLabels, moveCardToBoard } from '../../boards/relocate.js';\nimport { selectEventRule } from '../../rules/event-rules.js';\nimport type {\n FactoryGithubEventName,\n FactoryGithubRuleContext,\n FactoryRuleActor,\n FactoryRuleDecision,\n} from '../../rules/types.js';\nimport { assertFactoryDecisionTarget, validateFactoryRuleDecisions } from '../../rules/validation.js';\nimport { resolveIntakeLabelRoute } from '../../storage/domains/intake/base.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport type { IntegrationStorageHandle } from '../../storage/domains/integrations/base.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ExternalRepositoryProjectTarget,\n SourceControlStorageHandle,\n} from '../../storage/domains/source-control/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../../storage/domains/work-items/base.js';\nimport {\n FACTORY_PULL_REQUEST_RECONCILIATION_KEY,\n WorkItemUpdateConflictError,\n} from '../../storage/domains/work-items/base.js';\nimport type { IntegrationContext, IntegrationHooks } from '../base.js';\nimport { recordPullRequestHead } from '../pull-request-head.js';\nimport type { GithubAppIdentity } from './app-identity.js';\nimport type { GithubEventRules } from './default-rules.js';\nimport type { GithubRepositoryPermission } from './integration.js';\nimport { changeRequestTargetKey } from './subscriptions.js';\nimport type { ParsedGithubWebhook } from './webhook.js';\n\nconst TRUSTED_PERMISSIONS = new Set(['write', 'admin']);\nconst RULE_TIMEOUT_MS = 5_000;\nconst FACTORY_TRIAGE_COMMENT_MARKER = '<!-- mastra-factory-triage -->';\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction timestamp(value: unknown): number | undefined {\n const parsed = typeof value === 'string' ? Date.parse(value) : NaN;\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction string(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction number(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction boolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction actorLogins(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(actor => {\n const login = string(object(actor)?.login);\n return login ? [login] : [];\n });\n}\n\nfunction sameLabels(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((label, index) => label === b[index]);\n}\n\nfunction labelNames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(label => {\n if (typeof label === 'string') return label ? [label] : [];\n const name = string(object(label)?.name);\n return name ? [name] : [];\n });\n}\n\nfunction parseFactoryReviewCommand(\n body: string | undefined,\n target: string | undefined,\n): { command: 'review' | 're-review'; target: string } | undefined {\n if (!body || !target) return undefined;\n const firstLine = body\n .split('\\n')\n .map(line => line.trim())\n .find(line => line.length > 0)\n ?.toLowerCase();\n if (!firstLine) return undefined;\n const mention = `@${target.toLowerCase().replace(/\\[bot\\]$/, '')}`;\n if (firstLine === `${mention} review`) return { command: 'review', target };\n if (firstLine === `${mention} re-review`) return { command: 're-review', target };\n return undefined;\n}\n\nfunction eventName(parsed: ParsedGithubWebhook): FactoryGithubEventName | undefined {\n const action = string(parsed.payload.action);\n if (parsed.event === 'issues' && action === 'opened') return 'issueOpened';\n if (parsed.event === 'issues' && action === 'edited') {\n const changes = object(parsed.payload.changes);\n return object(changes?.title) || object(changes?.body) ? 'issueEdited' : undefined;\n }\n if (parsed.event === 'issues' && action === 'closed') return 'issueClosed';\n if (parsed.event === 'issue_comment') {\n const issue = object(parsed.payload.issue);\n // A comment on a PR arrives as `issue_comment` with `issue.pull_request` set.\n // It routes to the PR's own event so it binds to the authoring Work item via\n // provenance instead of being mistaken for a comment on an issue of the same\n // number. Only `created` matters: edits and deletions of an existing comment\n // are not new feedback to act on.\n if (object(issue?.pull_request)) {\n return action === 'created' ? 'pullRequestCommentCreated' : undefined;\n }\n if (action === 'created') return 'issueCommentCreated';\n if (action === 'edited') return 'issueCommentEdited';\n if (action === 'deleted') return 'issueCommentDeleted';\n }\n if (parsed.event === 'pull_request' && action === 'opened') return 'pullRequestOpened';\n if (parsed.event === 'pull_request' && action === 'synchronize') return 'pullRequestUpdated';\n if (parsed.event === 'pull_request' && action === 'closed') {\n return boolean(object(parsed.payload.pull_request)?.merged) ? 'pullRequestMerged' : 'pullRequestClosed';\n }\n if (parsed.event === 'pull_request' && action === 'review_requested') return 'pullRequestReviewRequested';\n if (parsed.event === 'pull_request_review' && action === 'submitted') return 'pullRequestReviewSubmitted';\n return undefined;\n}\n\n/**\n * Canonical source keys (`github-issue:N`, `github-pr:N`) do not identify a\n * repository, so a project linked to several repositories could bind repo A's\n * event to repo B's same-numbered card. The card's intake-stamped URL is\n * authoritative; the intake-stamped `githubRepositoryId` covers URL-less\n * cards. A card with neither signal cannot be attributed by number alone.\n */\nconst MAX_STALE_RULE_ATTEMPTS = 3;\n\nexport function cardBelongsToRepository(item: WorkItemRow, repositoryId: number, repositoryFullName: string): boolean {\n const url = item.externalSource?.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/(?:issues|pull)\\/\\d+(?:[/?#]|$)/.exec(url);\n if (match && match[1] === repositoryFullName) return true;\n }\n // A renamed repository leaves the old owner/name in the card URL, so a URL\n // mismatch still defers to the stable intake-stamped repository id.\n return item.metadata?.githubRepositoryId === repositoryId;\n}\n\nfunction canonicalSourceKey(kind: 'issue' | 'pull-request', itemNumber: number): string {\n return kind === 'issue' ? `github-issue:${itemNumber}` : `github-pr:${itemNumber}`;\n}\n\nfunction legacySourceKey(repositoryId: number, kind: 'issue' | 'pull-request', itemNumber: number): string {\n return `github:${repositoryId}:${kind}:${itemNumber}`;\n}\n\nfunction provenanceTarget(repositoryId: number, pullRequestNumber: number): string {\n return `factory-pr-provenance:${repositoryId}:${pullRequestNumber}`;\n}\n\nfunction workItemSource(item: WorkItemRow) {\n if (!item.externalSource) return 'manual' as const;\n return item.externalSource.type === 'pull-request' ? ('github-pr' as const) : ('github-issue' as const);\n}\n\nfunction workItemSourceKey(item: WorkItemRow): string | null {\n return item.externalSource?.externalId ?? null;\n}\n\n// Throws on a failed lookup: callers writing permanent state must retry, not\n// record the failure as distrust.\nexport async function trustedCollaborator(\n github: GithubRulesIntegration,\n input: { installationId: number; repository: string; login: string },\n): Promise<boolean> {\n const permission = await github.getRepositoryCollaboratorPermission(\n input.installationId,\n input.repository,\n input.login,\n );\n return permission !== undefined && TRUSTED_PERMISSIONS.has(permission);\n}\n\n// Terminal cards leave the reconcile loop below, so the ones that got there before author\n// trust was recorded have no other path to an answer.\nfunction authorAwaitingTrust(item: WorkItemRow, repository: ReconcileRepository): string | undefined {\n const metadata = item.metadata ?? {};\n if (typeof metadata.author !== 'string' || metadata.authorTrusted !== undefined) return undefined;\n const tracked = reconcilablePullRequestNumber(item, repository) ?? reconcilableIssueNumber(item, repository);\n if (tracked === undefined) return undefined;\n // A canonical key with no URL names no repository, and the pull request matcher takes it anyway.\n // Asking GitHub about the wrong repository of a multi-repository project would record a wrong answer.\n const unattributed =\n !item.externalSource?.url && /^github-(?:pr|issue):\\d+$/.test(item.externalSource?.externalId ?? '');\n if (unattributed && metadata.githubRepositoryId !== repository.id) return undefined;\n return metadata.author;\n}\n\nexport function sweepTrustLookup(\n github: GithubRulesIntegration,\n repository: ReconcileRepository,\n): (login: string) => Promise<boolean> {\n const cache = new Map<string, boolean>();\n return async login => {\n const cached = cache.get(login);\n if (cached !== undefined) return cached;\n const trusted = await trustedCollaborator(github, {\n installationId: repository.installationId,\n repository: repository.fullName,\n login,\n });\n cache.set(login, trusted);\n return trusted;\n };\n}\n\nasync function githubActor(\n github: GithubRulesIntegration,\n input: { installationId: number; repository: string; login: string; factoryAuthored: boolean },\n): Promise<FactoryRuleActor> {\n // The actor bit is recomputed on every event, so a failed lookup can read\n // untrusted for this one delivery instead of failing the ingest.\n const trusted = await trustedCollaborator(github, input).catch(() => false);\n return { type: 'github', login: input.login, trusted, factoryAuthored: input.factoryAuthored };\n}\n\ninterface FactoryPullRequestProvenanceData {\n kind: 'factory-pr-provenance';\n workItemId: string;\n}\n\nfunction pullRequestProvenance(\n data: Record<string, unknown> | undefined,\n factoryProjectId: string,\n): FactoryPullRequestProvenanceData | null {\n if (!data || data.kind !== 'factory-pr-provenance' || typeof data.workItemId !== 'string') return null;\n // Provenance proves which Factory *project's* run authored the PR. A row\n // written by a sibling project in the same org — or a legacy row without the\n // project stamp — fails closed here: honoring it would brand the PR\n // Factory-authored in a project that never touched it, and auto-start a\n // review that checks out and executes the PR there.\n if (data.factoryProjectId !== factoryProjectId) return null;\n return { kind: 'factory-pr-provenance', workItemId: data.workItemId };\n}\n\nexport interface GithubRulesIntegration {\n readonly rules: GithubEventRules;\n readonly slug?: string;\n /**\n * Factory's own GitHub login, used to ignore its own writes. Optional because\n * not every integration can name itself; when absent, self-recognition falls\n * back to the configured slug and, failing that, to content Factory stamps\n * itself (see `FACTORY_TRIAGE_COMMENT_MARKER`).\n */\n readonly identity?: GithubAppIdentity;\n getRepositoryCollaboratorPermission(\n installationId: number,\n repoFullName: string,\n username: string,\n ): Promise<GithubRepositoryPermission | undefined>;\n}\n\nexport interface GithubRulesOptions {\n github: GithubRulesIntegration;\n sourceControl: SourceControlStorageHandle;\n /** Integration-scoped storage; provenance rows are validated at read. */\n integrationStorage: IntegrationStorageHandle;\n projects: FactoryProjectsStorage;\n storage: WorkItemsStorage;\n configVersion: string;\n boards: BoardRegistry;\n /**\n * Decides which installed board an issue lands on: a label route first, then the repository's\n * intake source binding. Absent means Work.\n */\n intake?: Pick<IntakeStorage, 'listLabelRoutes' | 'listBindings'>;\n /** Hands a push to a linked repository off for an environment build. */\n onRepositoryPush?: IntegrationHooks['onRepositoryPush'];\n}\n\n/** Identity under which label-driven relocations are recorded. */\nconst LABEL_ROUTE_USER_ID = 'factory-rule-dispatcher';\n\nfunction issueLabelChange(parsed: ParsedGithubWebhook): boolean {\n const action = string(parsed.payload.action);\n return parsed.event === 'issues' && (action === 'labeled' || action === 'unlabeled');\n}\n\n/**\n * Whether a login is Factory itself. Prefers the resolved identity, which is\n * observed from Factory's own writes, and falls back to the configured slug.\n */\nexport function isFactoryGithubLogin(\n github: Pick<GithubRulesIntegration, 'identity' | 'slug'>,\n login: string | null | undefined,\n): boolean {\n if (github.identity?.known) return github.identity.matches(login);\n const slug = github.slug?.trim();\n if (!slug || !login) return false;\n return login.toLowerCase() === `${slug.toLowerCase()}[bot]`;\n}\n\nexport class GithubRules {\n constructor(private readonly options: GithubRulesOptions) {}\n\n /**\n * Whether a login is Factory itself. Prefers the resolved identity, which is\n * observed from Factory's own writes, and falls back to the configured slug.\n * An unset slug must not silently answer \"not Factory\" — that is what\n * disabled every self-loop guard.\n */\n #isFactoryLogin(login: string | undefined): boolean {\n return isFactoryGithubLogin(this.options.github, login);\n }\n\n #factoryMentionTarget(): string | undefined {\n const identity = this.options.github.identity;\n if (identity?.known) return identity.login;\n const slug = this.options.github.slug?.trim();\n return slug ? `${slug.toLowerCase()}[bot]` : undefined;\n }\n\n /**\n * Board an issue lands on: the one its labels select under the project's label routes, else the\n * board the repository's intake source binding names. Only installed boards count. Undefined\n * leaves built-in routing (Work) in charge.\n */\n async #intakeTarget(\n project: ExternalRepositoryProjectTarget,\n repositoryName: string,\n labels: readonly string[],\n ): Promise<{ board: string; initialPhase: string } | undefined> {\n const intake = this.options.intake;\n if (!intake) return undefined;\n const { orgId, factoryProjectId } = project;\n if (labels.length > 0) {\n const routes = await intake.listLabelRoutes({ orgId, factoryProjectId, integrationId: 'github' });\n const route = resolveIntakeLabelRoute(routes, labels);\n const board = route ? this.options.boards.get(route.board) : undefined;\n if (board) return { board: board.id, initialPhase: board.initialPhase };\n }\n // GitHub bindings are keyed by the internal repository id; the slug is accepted too since the\n // bindings API stores whatever source id it is given.\n const slug = repositoryName.toLowerCase();\n const binding = (await intake.listBindings({ orgId, integrationId: 'github' })).find(\n candidate =>\n candidate.factoryProjectId === factoryProjectId &&\n (candidate.sourceId === project.projectRepository.repositoryId || candidate.sourceId.toLowerCase() === slug),\n );\n const board = binding?.board ? this.options.boards.get(binding.board) : undefined;\n return board ? { board: board.id, initialPhase: board.initialPhase } : undefined;\n }\n\n /**\n * `labeled` / `unlabeled` are not rule events: the labels only decide which board the card belongs\n * on, so the card is re-routed here and its label metadata refreshed. Cards a run owns, and\n * finished cards, stay where they are.\n */\n async #relocateLabeledIssue(\n parsed: ParsedGithubWebhook,\n repositoryId: number,\n repositoryName: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'ignored' | 'committed' }> {\n const issue = object(parsed.payload.issue);\n const issueNumber = issue?.pull_request === undefined ? number(issue?.number) : undefined;\n if (!issueNumber) return { status: 'ignored' };\n const found = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n issueNumber,\n undefined,\n undefined,\n null,\n );\n if (!found || found.externalSource?.type !== 'issue') return { status: 'ignored' };\n const labels = labelNames(issue?.labels);\n let item = found;\n let changed = false;\n if (!sameLabels(cardLabels(item), labels)) {\n let updated;\n try {\n updated = await this.options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: LABEL_ROUTE_USER_ID,\n patch: { metadata: { ...(item.metadata ?? {}), labels } },\n expectedRevision: item.revision,\n });\n } catch (error) {\n // The card changed under us (a run wrote it, or a concurrent delivery won). The next\n // delivery or reconcile pass carries the same labels, so drop this one instead of 5xx-ing.\n if (!(error instanceof WorkItemUpdateConflictError)) throw error;\n return { status: 'ignored' };\n }\n if (!updated) return { status: 'ignored' };\n item = updated.item;\n changed = true;\n }\n const target = await this.#intakeTarget(project, repositoryName, labels);\n const outcome = await moveCardToBoard({\n workItems: this.options.storage,\n boardRegistry: this.options.boards,\n userId: LABEL_ROUTE_USER_ID,\n item,\n targetBoard: target?.board ?? 'work',\n });\n return { status: changed || outcome === 'moved' ? 'committed' : 'ignored' };\n }\n\n async ingest(parsed: ParsedGithubWebhook): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> {\n const event = eventName(parsed);\n const labelChange = issueLabelChange(parsed);\n const repository = object(parsed.payload.repository);\n const installationId = number(object(parsed.payload.installation)?.id);\n const repositoryId = number(repository?.id);\n const repositoryName = string(repository?.full_name);\n const login = string(object(parsed.payload.sender)?.login);\n if (parsed.event === 'push' && installationId && repositoryId) {\n await this.#handOffPush(parsed, installationId, repositoryId);\n return { status: 'ignored' };\n }\n if ((!event && !labelChange) || !installationId || !repositoryId || !repositoryName || !login) {\n return { status: 'ignored' };\n }\n\n const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(installationId),\n repositoryExternalId: String(repositoryId),\n });\n if (projects.length === 0) return { status: 'ignored' };\n const results = [];\n for (const project of projects) {\n results.push(\n event\n ? await this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project)\n : await this.#relocateLabeledIssue(parsed, repositoryId, repositoryName, project),\n );\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n /**\n * A push is not a work-item event; it only reaches the environment build\n * hand-off, once per project the repository is linked to. The hook decides\n * whether the project builds on push.\n */\n async #handOffPush(parsed: ParsedGithubWebhook, installationId: number, repositoryId: number): Promise<void> {\n const onRepositoryPush = this.options.onRepositoryPush;\n const ref = string(parsed.payload.ref);\n const defaultBranch = string(object(parsed.payload.repository)?.default_branch);\n if (!onRepositoryPush || !ref || !defaultBranch) return;\n const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(installationId),\n repositoryExternalId: String(repositoryId),\n });\n for (const project of projects) {\n onRepositoryPush({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n projectRepository: {\n id: project.projectRepository.id,\n inEnvironment: project.projectRepository.inEnvironment,\n },\n ref,\n defaultBranch,\n });\n }\n }\n\n async #ingestProject(\n parsed: ParsedGithubWebhook,\n event: FactoryGithubEventName,\n installationId: number,\n repositoryId: number,\n repositoryName: string,\n login: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> {\n const factoryProject = await this.options.projects.get({\n orgId: project.orgId,\n id: project.factoryProjectId,\n });\n if (!factoryProject) return { status: 'missing' };\n const issue = object(parsed.payload.issue);\n const issueComment = object(parsed.payload.comment);\n const changes = object(parsed.payload.changes);\n // A comment on a PR carries the PR under `issue` (with `pull_request` set)\n // and has no `pull_request` payload of its own. Read the PR from `issue` in\n // that case so provenance and `context.pullRequest` behave as they do for\n // every other PR event, and so the number is never treated as an issue's.\n const commentOnPullRequest = object(parsed.payload.issue)?.pull_request !== undefined;\n const pullRequest = object(parsed.payload.pull_request) ?? (commentOnPullRequest ? issue : undefined);\n const issueNumber = commentOnPullRequest ? undefined : number(issue?.number);\n const pullRequestNumber = number(pullRequest?.number);\n const provenance = pullRequestNumber\n ? pullRequestProvenance(\n (\n await this.options.integrationStorage.subscriptions.listByTarget(\n provenanceTarget(repositoryId, pullRequestNumber),\n { status: 'active' },\n )\n ).find(\n subscription =>\n subscription.orgId === project.orgId && subscription.data?.factoryProjectId === project.factoryProjectId,\n )?.data,\n project.factoryProjectId,\n )\n : null;\n // Re-review events target the PR's own Review card, not the Work item that\n // provenance would otherwise bind the event to. For review_requested the\n // sender is whoever clicked re-request, so a Factory-authored PR must not\n // brand a human requester as factory-authored.\n const reviewRequested = event === 'pullRequestReviewRequested';\n const reviewCommand =\n event === 'pullRequestCommentCreated'\n ? parseFactoryReviewCommand(string(issueComment?.body), this.#factoryMentionTarget())\n : undefined;\n const reviewEntryRequested = reviewRequested || reviewCommand !== undefined;\n // Provenance proves the *pull request* came from Factory, which is not the\n // same as the sender of this event. For events where the sender is whoever\n // reacted to the PR — re-requesting review, commenting, submitting a review\n // — branding them from provenance would mark every human and every review\n // bot as Factory. Only the app login identifies Factory for those.\n const senderIsResponder =\n reviewRequested || event === 'pullRequestCommentCreated' || event === 'pullRequestReviewSubmitted';\n const reReviewEvent = reviewEntryRequested || event === 'pullRequestUpdated';\n const requestedReviewer = string(object(parsed.payload.requested_reviewer)?.login);\n const pullRequestAuthor = string(object(pullRequest?.user)?.login);\n const pullRequestFactoryAuthored = provenance !== null || this.#isFactoryLogin(pullRequestAuthor);\n const resolvedItem = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n issueNumber,\n pullRequestNumber,\n string(object(pullRequest?.head)?.ref),\n reReviewEvent ? null : provenance,\n senderIsResponder && !reviewEntryRequested,\n );\n // A review-entry request must never treat a branch-matched authoring Work\n // card as the PR's Review card. A missing Review card is materialized below.\n const relatedItem =\n reviewEntryRequested && resolvedItem?.externalSource?.type !== 'pull-request' ? undefined : resolvedItem;\n const intake = issueNumber\n ? await this.#intakeTarget(project, repositoryName, labelNames(issue?.labels))\n : undefined;\n const actor = await githubActor(this.options.github, {\n installationId,\n repository: repositoryName,\n login,\n factoryAuthored: (!senderIsResponder && provenance !== null) || this.#isFactoryLogin(login),\n });\n // A marked handoff comment is ignored only when Factory authored it: a\n // human may quote the marker to add an investigation lead, and that must\n // still retrigger triage. Recognising the author is therefore the whole\n // guard — when identity cannot be resolved this fails open and Factory's\n // own handoff cancels the run that wrote it.\n if (\n actor.type === 'github' &&\n actor.factoryAuthored &&\n (event === 'issueCommentCreated' || event === 'issueCommentEdited') &&\n string(issueComment?.body)?.includes(FACTORY_TRIAGE_COMMENT_MARKER)\n ) {\n return { status: 'ignored' };\n }\n // One delivery can concern two cards — a merged pull request settles both\n // its own Review card and the Work item that authored it — and every\n // decision a rule returns is committed against a single item, at that\n // item's revision. So the evaluation, not the decision, is what fans out:\n // the rule runs once per bound item, each with its own ingress identity.\n const evaluate = async (\n item: WorkItemRow | undefined,\n ingressIdentity: string,\n /** Set on the evaluation that files the pull request's own Review card. */\n pullRequestIntake = false,\n attempt = 1,\n ): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> => {\n const context: FactoryGithubRuleContext = {\n tenant: { orgId: project.orgId, projectId: project.factoryProjectId },\n actor,\n ingress: { type: 'github', id: ingressIdentity },\n cause: `github.${event}`,\n causalChain: [],\n configVersion: this.options.configVersion,\n ...(item\n ? {\n item: {\n id: item.id,\n source: workItemSource(item),\n sourceKey: workItemSourceKey(item),\n parentWorkItemId: item.parentWorkItemId,\n title: item.title,\n url: item.externalSource?.url ?? null,\n stages: item.stages,\n acceptedAt: item.acceptedAt,\n metadata: item.metadata,\n },\n board: boardForWorkItem(item),\n itemRevision: item.revision,\n ...withBoardClosure(this.options.boards, item),\n ...rulePhaseField(this.options.boards, item),\n }\n : {}),\n ...(intake ? { intake } : {}),\n ...(pullRequestIntake ? { pullRequestIntake: true } : {}),\n event,\n deliveryId: parsed.deliveryId,\n factory: { createdAt: factoryProject.createdAt.toISOString() },\n repository: { id: repositoryId, fullName: repositoryName, installationId },\n ...(issueNumber && string(issue?.title) && string(issue?.html_url)\n ? {\n issue: {\n number: issueNumber,\n title: string(issue?.title)!,\n url: string(issue?.html_url)!,\n ...(string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}),\n ...(string(issue?.updated_at) ? { updatedAt: string(issue?.updated_at) } : {}),\n assignees: actorLogins(issue?.assignees),\n labels: labelNames(issue?.labels),\n ...(string(issue?.state) === 'closed' || string(issue?.state) === 'open'\n ? { state: string(issue?.state) as 'open' | 'closed' }\n : {}),\n ...(string(issue?.state_reason) ? { stateReason: string(issue?.state_reason) } : {}),\n },\n }\n : {}),\n ...(event === 'issueEdited'\n ? { issueChange: { title: Boolean(object(changes?.title)), body: Boolean(object(changes?.body)) } }\n : {}),\n ...(number(issueComment?.id)\n ? {\n issueComment: {\n id: number(issueComment?.id)!,\n ...(string(issueComment?.body) ? { body: string(issueComment?.body) } : {}),\n ...(string(issueComment?.html_url) ? { url: string(issueComment?.html_url) } : {}),\n ...(string(object(issueComment?.user)?.login)\n ? { author: string(object(issueComment?.user)?.login) }\n : {}),\n ...(string(object(issueComment?.user)?.type)\n ? { authorType: string(object(issueComment?.user)?.type) }\n : {}),\n ...(string(issueComment?.created_at) ? { createdAt: string(issueComment?.created_at) } : {}),\n ...(string(issueComment?.updated_at) ? { updatedAt: string(issueComment?.updated_at) } : {}),\n },\n }\n : {}),\n ...(pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url)\n ? {\n pullRequest: {\n number: pullRequestNumber,\n title: string(pullRequest?.title)!,\n url: string(pullRequest?.html_url)!,\n ...(string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {}),\n state: string(pullRequest?.state) === 'closed' ? ('closed' as const) : ('open' as const),\n draft: boolean(pullRequest?.draft) ?? false,\n merged: boolean(pullRequest?.merged) ?? false,\n assignees: actorLogins(pullRequest?.assignees),\n requestedReviewers: actorLogins(pullRequest?.requested_reviewers),\n labels: labelNames(pullRequest?.labels),\n ...(pullRequestAuthor ? { author: pullRequestAuthor } : {}),\n factoryAuthored: pullRequestFactoryAuthored,\n headBranch: string(object(pullRequest?.head)?.ref) ?? '',\n baseBranch: string(object(pullRequest?.base)?.ref) ?? '',\n },\n }\n : {}),\n ...(reviewRequested && requestedReviewer\n ? {\n reviewRequest: {\n reviewer: requestedReviewer,\n factoryReviewer: this.#isFactoryLogin(requestedReviewer),\n },\n }\n : {}),\n ...(reviewCommand ? { reviewCommand } : {}),\n ...(object(parsed.payload.review)\n ? {\n review: {\n id: number(object(parsed.payload.review)?.id) ?? 0,\n state: string(object(parsed.payload.review)?.state) ?? 'unknown',\n url: string(object(parsed.payload.review)?.html_url) ?? '',\n ...(string(object(object(parsed.payload.review)?.user)?.login)\n ? { author: string(object(object(parsed.payload.review)?.user)?.login) }\n : {}),\n ...(string(object(parsed.payload.review)?.body)\n ? { body: string(object(parsed.payload.review)?.body) }\n : {}),\n },\n }\n : {}),\n };\n\n const rule = selectEventRule(\n this.options.github.rules,\n boardEventHandlers(this.options.boards, eventBoardId(context), 'github'),\n event,\n );\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => {\n assertFactoryDecisionTarget(entry, this.options.boards, item ? boardForWorkItem(item) : undefined);\n return { ...entry };\n });\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory GitHub rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n workItemId: item?.id ?? null,\n ingress: { identity: ingressIdentity, triggerType: `github.${event}` },\n configVersion: this.options.configVersion,\n expectedRevision: item?.revision ?? null,\n actor: { ...actor },\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n if (committed.status === 'stale') {\n // The item was written concurrently. Re-read it and run the rule again\n // against the fresh revision; nothing was persisted for this attempt.\n if (attempt >= MAX_STALE_RULE_ATTEMPTS) {\n throw new Error(`Factory GitHub rule evaluation for ${ingressIdentity} kept losing revision races.`);\n }\n const fresh = item ? await this.options.storage.get({ orgId: project.orgId, id: item.id }) : null;\n if (item && !fresh) return { status: 'missing' };\n return evaluate(fresh ?? undefined, ingressIdentity, pullRequestIntake, attempt + 1);\n }\n return { status: committed.status };\n };\n\n // A push moves the head a recorded review verdict was given on. Recording\n // the new head lets the verdict badge show that it is outdated, while the\n // verdict itself stays so the next pass still runs as a re-review. It is\n // recorded before the push is evaluated: the dispatcher can apply the\n // re-review transition as soon as it commits, and the pass it starts names\n // the head it covers, which must be the pushed one.\n const stampHead = async () => {\n const headSha = string(object(pullRequest?.head)?.sha)?.toLowerCase();\n if (event !== 'pullRequestUpdated' || !headSha || !pullRequestNumber) return;\n const headAt = timestamp(pullRequest?.updated_at);\n if (relatedItem?.externalSource?.type !== 'pull-request') return;\n const parent = await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n relatedItem,\n );\n // The authoring Work item mirrors the verdict of the pull request it has\n // out; a push to an older one must not mark its successor's verdict.\n await recordPullRequestHead(this.options.storage, {\n orgId: relatedItem.orgId,\n id: relatedItem.id,\n headSha,\n headAt,\n });\n if (parent) {\n await recordPullRequestHead(this.options.storage, {\n orgId: parent.orgId,\n id: parent.id,\n headSha,\n headAt,\n ownedPullRequestNumber: pullRequestNumber,\n });\n }\n };\n await stampHead();\n const evaluated =\n event === 'pullRequestUpdated' && relatedItem\n ? ((await this.options.storage.get({ orgId: relatedItem.orgId, id: relatedItem.id })) ?? relatedItem)\n : relatedItem;\n const deliveryIdentity = `${installationId}:${parsed.deliveryId}`;\n // A pull request opening concerns two cards: its own Review card, which the\n // arrival rule files — committed against the Work item that authored the\n // pull request when one exists, because that binding is what links the two\n // — and that authoring item, which is now out for review. The arrival is\n // the delivery's own evaluation; the item's is a second one, under an\n // identity suffixed with its id, because ingress identities are the replay\n // key and reusing the delivery's own would drop it as a duplicate.\n const pullRequestOpened = event === 'pullRequestOpened';\n const primary = await evaluate(evaluated, deliveryIdentity, pullRequestOpened);\n // A closed pull request is the one *other* event both linked cards need:\n // the Review card has to close, and the Work item that wrote the code has\n // to finish (on merge) or at least stop recording it as open. Resolution binds the delivery to\n // whichever card it matched first, so evaluate the other one too.\n const linked =\n (event === 'pullRequestMerged' || event === 'pullRequestClosed') && relatedItem && pullRequestNumber\n ? await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n relatedItem,\n )\n : undefined;\n // Moving the card to Done does not touch its pull request fields, so without\n // this the card reads \"open\" until the next sweep and still offers Re-review.\n // Stamped after the evaluations, which commit at the revision they read.\n const stampClosed = async (companionStatus?: string) => {\n if (!pullRequestNumber) return;\n // The authoring Work item records which pull request it has out, so an\n // agent cannot close the work while that pull request is still open.\n if (pullRequestOpened) {\n // Mirrors the out-for-review rule's trust gate. A replayed opened\n // delivery only restores the mark (after a failed write) while the\n // pull request's Review card still records it open, so a redelivery\n // after the close cannot block the Work item again.\n const trusted = (actor.type === 'github' && actor.trusted) || pullRequestFactoryAuthored;\n const reviewCard =\n authoringItem && trusted\n ? await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n authoringItem,\n )\n : undefined;\n const stillOpen =\n companionStatus === 'replayed'\n ? reviewCard !== undefined && reviewCard.metadata?.state !== 'closed'\n : reviewCard?.metadata?.state !== 'closed';\n if (authoringItem && trusted && stillOpen) {\n // The head comes along so a head recorded for an earlier pull\n // request cannot mark this one's verdict outdated. A replayed opening\n // of the pull request already recorded keeps the head its pushes left.\n const rebinding = authoringItem.metadata?.openPullRequestNumber !== pullRequestNumber;\n const head = rebinding\n ? {\n pullRequestHeadSha: string(object(pullRequest?.head)?.sha)?.toLowerCase() ?? null,\n pullRequestHeadAt: timestamp(pullRequest?.updated_at) ?? null,\n }\n : {};\n await this.options.storage.update({\n orgId: authoringItem.orgId,\n id: authoringItem.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { openPullRequestNumber: pullRequestNumber, ...head } },\n });\n }\n return;\n }\n if (event !== 'pullRequestMerged' && event !== 'pullRequestClosed') return;\n for (const card of [relatedItem, linked]) {\n if (!card) continue;\n if (card.externalSource?.type !== 'pull-request') {\n // A merge settles the review, so the authoring Work item's mirrored\n // \"request changes\" no longer stops it from being closed.\n // Only the pull request the card has out settles it; an older one\n // merging must not clear a verdict that belongs to its successor.\n const recorded = card.metadata?.openPullRequestNumber;\n const ownsCard = typeof recorded !== 'number' || recorded === pullRequestNumber;\n const settled = {\n ...(ownsCard && event === 'pullRequestMerged' && typeof card.metadata?.reviewVerdict === 'string'\n ? { reviewVerdict: null }\n : {}),\n ...(recorded === pullRequestNumber ? { openPullRequestNumber: null } : {}),\n };\n if (Object.keys(settled).length > 0) {\n await this.options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: settled },\n });\n }\n continue;\n }\n await this.options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { state: 'closed', merged: event === 'pullRequestMerged' } },\n });\n }\n };\n const authoringItem =\n linked === undefined &&\n pullRequestOpened &&\n relatedItem !== undefined &&\n relatedItem.externalSource?.type !== 'pull-request'\n ? relatedItem\n : undefined;\n if (linked === undefined && authoringItem === undefined) {\n await stampClosed();\n return primary;\n }\n const companion = linked ?? authoringItem;\n const secondary = await evaluate(companion, `${deliveryIdentity}:${companion?.id ?? 'pull-request'}`);\n await stampClosed(secondary.status);\n for (const status of ['committed', 'replayed'] as const) {\n if (primary.status === status || secondary.status === status) return { status };\n }\n return primary;\n }\n\n /**\n * The other card a closed pull request concerns, joined through the Review\n * card's `parentWorkItemId` — the link `upsertLinkedWorkItem` records when the\n * pull request is opened, and therefore an exact join that needs no branch\n * heuristics. Returns nothing when the pull request has only one card, which\n * is every pull request Factory did not open from a work item's session.\n */\n async #linkedClosureItem(\n orgId: string,\n projectId: string,\n repositoryId: number,\n repositoryFullName: string,\n pullRequestNumber: number,\n resolved: WorkItemRow,\n ): Promise<WorkItemRow | undefined> {\n const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });\n const linked =\n resolved.externalSource?.type === 'pull-request'\n ? // Bound to the pull request's own Review card: follow the recorded\n // link back to the work item that authored it.\n items.find(item => item.id === resolved.parentWorkItemId)\n : // Bound to the work item (provenance): find the Review card this pull\n // request opened, and only when it names this item as its parent — a\n // card for the same number in another repository is not this one's.\n items.find(\n item =>\n item.parentWorkItemId === resolved.id &&\n (item.externalSource?.externalId === canonicalSourceKey('pull-request', pullRequestNumber) ||\n item.externalSource?.externalId === legacySourceKey(repositoryId, 'pull-request', pullRequestNumber)) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n );\n return linked?.id === resolved.id ? undefined : linked;\n }\n\n async #relatedItem(\n orgId: string,\n projectId: string,\n repositoryId: number,\n repositoryFullName: string,\n issueNumber: number | undefined,\n pullRequestNumber: number | undefined,\n pullRequestHeadBranch: string | undefined,\n provenance: FactoryPullRequestProvenanceData | null,\n preferAuthoringItem = false,\n ): Promise<WorkItemRow | undefined> {\n const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });\n const resolved = this.#resolveItem(\n items,\n repositoryId,\n repositoryFullName,\n issueNumber,\n pullRequestNumber,\n pullRequestHeadBranch,\n provenance,\n );\n // Feedback on a pull request has to reach the item that *wrote* the code.\n // Provenance normally lands it there directly, but when provenance is\n // missing the PR-number lookup wins and returns the PR's own Review card\n // instead — a board the feedback rules deliberately refuse to act on, so\n // the wake is silently dropped. The linked card records its author in\n // `parentWorkItemId`, so follow that link back rather than relaxing the\n // guard, which would let a Review card react to its own posted review.\n if (preferAuthoringItem && resolved?.externalSource?.type === 'pull-request' && resolved.parentWorkItemId) {\n return items.find(item => item.id === resolved.parentWorkItemId) ?? resolved;\n }\n return resolved;\n }\n\n #resolveItem(\n items: WorkItemRow[],\n repositoryId: number,\n repositoryFullName: string,\n issueNumber: number | undefined,\n pullRequestNumber: number | undefined,\n pullRequestHeadBranch: string | undefined,\n provenance: FactoryPullRequestProvenanceData | null,\n ): WorkItemRow | undefined {\n if (provenance) return items.find(item => item.id === provenance.workItemId);\n if (issueNumber) {\n return (\n items.find(\n item =>\n item.externalSource?.externalId === canonicalSourceKey('issue', issueNumber) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n ) ?? items.find(item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'issue', issueNumber))\n );\n }\n if (pullRequestNumber) {\n return (\n items.find(\n item =>\n item.externalSource?.externalId === canonicalSourceKey('pull-request', pullRequestNumber) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n ) ??\n items.find(\n item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'pull-request', pullRequestNumber),\n ) ??\n // Provenance fallback: a PR pushed from a work item's session branch\n // belongs to that item even when no gh-pr-create provenance was\n // recorded (session predating state seeding, or the PR was opened\n // outside the tracked tool call). Session branches are per-item\n // (`factory/issue-N`), so a head-branch match is unambiguous.\n (pullRequestHeadBranch\n ? items.find(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === pullRequestHeadBranch),\n )\n : undefined)\n );\n }\n return undefined;\n }\n}\n\nexport interface ReconcilePullRequestState {\n title: string;\n url: string;\n state: 'open' | 'closed';\n draft: boolean;\n merged: boolean;\n assignees?: string[];\n requestedReviewers?: string[];\n labels?: string[];\n headBranch: string;\n baseBranch: string;\n author?: string;\n createdAt?: string;\n mergedBy?: string;\n}\n\nexport interface PolledPullRequestState extends ReconcilePullRequestState {\n createdAt: string;\n}\n\nexport type GithubPullRequestFetcher = (input: {\n installationId: number;\n repository: string;\n number: number;\n}) => Promise<ReconcilePullRequestState | undefined>;\n\nexport interface ReconcileIssueState {\n title: string;\n url: string;\n state: 'open' | 'closed';\n /** GitHub close reason: `completed`, `not_planned`, or `duplicate`. */\n stateReason?: string;\n assignees?: string[];\n labels?: string[];\n author?: string;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport type GithubIssueFetcher = (input: {\n installationId: number;\n repository: string;\n number: number;\n}) => Promise<ReconcileIssueState | undefined>;\n\n/** Lists a repository's open issues (pull requests excluded) for missed-open discovery. */\nexport type GithubOpenIssueLister = (input: {\n installationId: number;\n repository: string;\n}) => Promise<Array<ReconcileIssueState & { number: number }>>;\n\nexport interface ReconcileRepository {\n id: number;\n fullName: string;\n installationId: number;\n}\n\nexport interface ReconcileSweepSummary {\n /** Factory-configured repositories included in the sweep. */\n repositories: number;\n /** PRs whose live state was fetched from GitHub. */\n checked: number;\n /** Missed merges replayed through the rules ingress. */\n merged: number;\n /** Missed closes-without-merge replayed through the rules ingress. */\n closed: number;\n /** PRs/issues (or whole repositories) skipped because of an error. */\n failed: number;\n /** Error samples with context, capped at {@link RECONCILE_ERROR_SAMPLE_LIMIT}. */\n errors: Array<{ repository: string; pullRequestNumber?: number; issueNumber?: number; error: string }>;\n}\n\nexport type GithubPullRequestReconciler = (repositories: ReconcileRepository[]) => Promise<ReconcileSweepSummary>;\n\nexport const RECONCILE_ERROR_SAMPLE_LIMIT = 5;\n\nexport function sameStrings(left: unknown, right: string[] | undefined): boolean {\n if (right === undefined) return true;\n if (!Array.isArray(left)) return false;\n const leftValues = new Set(left.flatMap(value => (typeof value === 'string' ? [value] : [])));\n const rightValues = new Set(right);\n return leftValues.size === rightValues.size && [...leftValues].every(value => rightValues.has(value));\n}\n\n/**\n * Extracts the PR number a work item tracks, but only when the item belongs\n * to the given repository. Card URLs pin the repository unambiguously; the\n * legacy source key embeds the repository id. Canonical keys (`github-pr:N`)\n * carry no repository, so they are only trusted when the item has no URL —\n * a project mapped to multiple repositories must not reconcile one repo's\n * card against another repo's PR number.\n */\nfunction reconcilablePullRequestNumber(item: WorkItemRow, repository: ReconcileRepository): number | undefined {\n if (item.externalSource?.type !== 'pull-request') return undefined;\n const url = item.externalSource.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/pull\\/(\\d+)(?:[/?#]|$)/.exec(url);\n if (!match) return undefined;\n return match[1] === repository.fullName ? Number(match[2]) : undefined;\n }\n const externalId = item.externalSource.externalId;\n const legacy = /^github:(\\d+):pull-request:(\\d+)$/.exec(externalId);\n if (legacy) return Number(legacy[1]) === repository.id ? Number(legacy[2]) : undefined;\n const canonical = /^github-pr:(\\d+)$/.exec(externalId);\n return canonical ? Number(canonical[1]) : undefined;\n}\n\n/**\n * Extracts the issue number a work item tracks, but only when the item\n * belongs to the given repository. Stricter than\n * {@link reconcilablePullRequestNumber}: a canonical key with no URL is only\n * trusted when the intake-stamped `githubRepositoryId` confirms the\n * repository, because the sweep initiates closes on its own.\n */\nexport function reconcilableIssueNumber(item: WorkItemRow, repository: ReconcileRepository): number | undefined {\n if (item.externalSource?.type !== 'issue') return undefined;\n const url = item.externalSource.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/issues\\/(\\d+)(?:[/?#]|$)/.exec(url);\n if (!match) return undefined;\n // A renamed repository leaves the old owner/name in the card URL, so a\n // URL mismatch still defers to the stable intake-stamped repository id.\n const belongs = match[1] === repository.fullName || item.metadata?.githubRepositoryId === repository.id;\n return belongs ? Number(match[2]) : undefined;\n }\n const externalId = item.externalSource.externalId;\n const legacy = /^github:(\\d+):issue:(\\d+)$/.exec(externalId);\n if (legacy) return Number(legacy[1]) === repository.id ? Number(legacy[2]) : undefined;\n const canonical = /^github-issue:(\\d+)$/.exec(externalId);\n if (!canonical) return undefined;\n // Canonical keys carry no repository; only the intake-stamped repository id\n // can attribute a URL-less card, and guessing would let a multi-repo\n // project close repo B's card because repo A's same-numbered issue closed.\n return item.metadata?.githubRepositoryId === repository.id ? Number(canonical[1]) : undefined;\n}\n\nexport function reconciledIssueClosedEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n return {\n event: 'issues',\n // Stable per (repository, issue): the ingress dedupe makes repeat\n // reconcile cycles replay instead of re-committing decisions.\n deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:closed`,\n payload: {\n action: 'closed',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? 'github' },\n issue: {\n number: issueNumber,\n title: state.title,\n html_url: state.url,\n state: 'closed',\n ...(state.stateReason ? { state_reason: state.stateReason } : {}),\n ...(state.createdAt ? { created_at: state.createdAt } : {}),\n ...(state.updatedAt ? { updated_at: state.updatedAt } : {}),\n assignees: githubUsers(state.assignees),\n },\n },\n };\n}\n\n/**\n * The label-drift replay: an open issue whose labels changed without a\n * `labeled`/`unlabeled` webhook ever arriving (Factory was down, the delivery\n * was lost, or the label was applied by something other than a delivery the\n * webhook saw). Synthesized as an `opened` delivery so the deployment's\n * `issueOpened` rule decides placement, exactly as it does at arrival — one\n * source of placement policy for both.\n */\nexport function reconciledIssueRelabeledEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n const labels = state.labels ?? [];\n // GitHub updates `updated_at` for a label change. Including it makes retries\n // of one observed issue version idempotent while allowing A → B → A to replay\n // its final A placement as a new version. Synthetic callers without it retain\n // the legacy label-only identity.\n const digest = createHash('sha256')\n .update([...labels].sort().join('\\n'))\n .digest('hex')\n .slice(0, 16);\n const version = state.updatedAt ? `:${createHash('sha256').update(state.updatedAt).digest('hex').slice(0, 16)}` : '';\n return {\n event: 'issues',\n deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:relabeled:${digest}${version}`,\n payload: {\n // `opened` is the event that carries an issue's labels through the rules;\n // an already-filed card is re-placed by the decision, not re-materialized.\n action: 'opened',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? 'github' },\n issue: {\n number: issueNumber,\n title: state.title,\n html_url: state.url,\n state: 'open',\n ...(state.createdAt ? { created_at: state.createdAt } : {}),\n ...(state.updatedAt ? { updated_at: state.updatedAt } : {}),\n assignees: githubUsers(state.assignees),\n labels: githubLabels(labels),\n },\n },\n };\n}\n\n/**\n * The missed-open replay: an open issue with no Work card, because its\n * `opened` delivery never reached the rules ingress. Synthesized as the same\n * `opened` delivery so the deployment's `issueOpened` rule decides whether and\n * where it lands, exactly as it would have at arrival. The delivery id is\n * stable per issue so repeat sweeps dedupe at the ingress.\n */\nexport function reconciledIssueOpenedEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n const event = reconciledIssueRelabeledEvent(repository, issueNumber, state);\n return { ...event, deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:opened` };\n}\n\nexport function polledPullRequestEvent(\n repository: ReconcileRepository,\n pullRequestNumber: number,\n state: PolledPullRequestState,\n): ParsedGithubWebhook {\n return {\n event: 'pull_request',\n deliveryId: `poll:${repository.id}:pull-request:${pullRequestNumber}:${state.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? '__unknown__' },\n pull_request: pullRequestPayload(pullRequestNumber, state),\n },\n };\n}\n\nexport function reconciledClosedEvent(\n repository: ReconcileRepository,\n pullRequestNumber: number,\n state: ReconcilePullRequestState,\n): ParsedGithubWebhook {\n const outcome = state.merged ? 'merged' : 'closed';\n return {\n event: 'pull_request',\n // Stable per (repository, PR, outcome): the ingress dedupe makes repeat\n // reconcile cycles replay instead of re-committing decisions.\n deliveryId: `reconcile:${repository.id}:pull-request:${pullRequestNumber}:${outcome}`,\n payload: {\n action: 'closed',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.mergedBy ?? 'github' },\n pull_request: pullRequestPayload(pullRequestNumber, { ...state, state: 'closed' }),\n },\n };\n}\n\nfunction pullRequestPayload(pullRequestNumber: number, state: ReconcilePullRequestState): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n number: pullRequestNumber,\n title: state.title,\n html_url: state.url,\n state: state.state,\n draft: state.draft,\n merged: state.merged,\n assignees: githubUsers(state.assignees),\n requested_reviewers: githubUsers(state.requestedReviewers),\n labels: githubLabels(state.labels),\n head: { ref: state.headBranch },\n base: { ref: state.baseBranch },\n };\n if (state.createdAt) payload.created_at = state.createdAt;\n if (state.author) payload.user = { login: state.author };\n return payload;\n}\n\nfunction githubUsers(logins: readonly string[] = []): Array<{ login: string }> {\n return logins.map(login => ({ login }));\n}\n\nfunction githubLabels(names: readonly string[] = []): Array<{ name: string }> {\n return names.map(name => ({ name }));\n}\n\nfunction reconciledPullRequestMetadata(\n state: ReconcilePullRequestState,\n reconciliation: 'clear' | 'settled',\n authorTrusted?: boolean,\n): Record<string, unknown> {\n return {\n state: state.state,\n draft: state.draft,\n merged: state.merged,\n ...(state.author ? { author: state.author } : {}),\n ...(state.assignees ? { assignees: state.assignees } : {}),\n ...(state.requestedReviewers ? { requestedReviewers: state.requestedReviewers } : {}),\n ...(state.labels ? { labels: state.labels } : {}),\n ...(authorTrusted === undefined ? {} : { authorTrusted }),\n [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]:\n reconciliation === 'settled' ? (state.merged ? 'merged' : 'closed') : null,\n };\n}\n\nfunction reconciledPullRequestOutcome(metadata: Record<string, unknown>): 'merged' | 'closed' | undefined {\n if (metadata.state !== 'closed' || typeof metadata.merged !== 'boolean') return undefined;\n return metadata.merged ? 'merged' : 'closed';\n}\n\n/**\n * The webhook handler retires subscriptions itself; the sweep replays only the\n * rules ingress, so without this the thread's PR chip and the workspace row\n * stay `open` forever on a deployment GitHub cannot reach.\n */\nasync function retireReconciledSubscriptions(\n storage: IntegrationStorageHandle,\n repository: ReconcileRepository,\n pullRequestNumber: number,\n merged: boolean,\n): Promise<void> {\n const target = changeRequestTargetKey({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n changeRequestId: String(pullRequestNumber),\n });\n const rows = await storage.subscriptions.listByTarget(target);\n await Promise.all(\n rows\n .filter(row => row.status === 'open')\n .map(row => storage.subscriptions.updateStatus(row.id, merged ? 'merged' : 'closed')),\n );\n}\n\n/**\n * State-based safety net for merge signals: webhooks and event-log tailing\n * can miss a merge (cursor gaps, downtime, terminally failed decisions), so\n * this sweep compares still-open PR cards against actual GitHub state and\n * replays the merge through the normal rules ingress when they disagree.\n */\nexport function createGithubPullRequestReconciler(\n options: GithubRulesOptions,\n fetchPullRequest: GithubPullRequestFetcher,\n): GithubPullRequestReconciler {\n const rules = new GithubRules(options);\n return async repositories => {\n const summary: ReconcileSweepSummary = {\n repositories: 0,\n checked: 0,\n merged: 0,\n closed: 0,\n failed: 0,\n errors: [],\n };\n const recordFailure = (repository: ReconcileRepository, error: unknown, pullRequestNumber?: number) => {\n summary.failed += 1;\n if (summary.errors.length < RECONCILE_ERROR_SAMPLE_LIMIT) {\n summary.errors.push({\n repository: repository.fullName,\n ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n };\n // An installation can expose hundreds of repositories; only the ones\n // actually linked to a factory project can have cards to reconcile, so\n // scope the sweep to those up front instead of probing each repository.\n const configured = new Set(\n (await options.sourceControl.projectRepositories.listConfiguredExternalKeys()).map(\n key => `${key.installationExternalId}\\u0000${key.repositoryExternalId}`,\n ),\n );\n const scoped = repositories.filter(repository =>\n configured.has(`${repository.installationId}\\u0000${repository.id}`),\n );\n summary.repositories = scoped.length;\n for (const repository of scoped) {\n // One broken repository (or a failing token exchange for its\n // installation) must not abort the sweep for the others.\n let cardsByNumber: Map<number, WorkItemRow[]>;\n let unanswered: Array<{ item: WorkItemRow; author: string }>;\n try {\n const projects = await options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n });\n if (projects.length === 0) continue;\n cardsByNumber = new Map<number, WorkItemRow[]>();\n unanswered = [];\n for (const project of projects) {\n const items = await options.storage.list({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n });\n for (const item of items) {\n const unansweredAuthor = authorAwaitingTrust(item, repository);\n if (unansweredAuthor) unanswered.push({ item, author: unansweredAuthor });\n const pullRequestNumber = reconcilablePullRequestNumber(item, repository);\n if (!pullRequestNumber) continue;\n const metadata = item.metadata ?? {};\n const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];\n const reconciledOutcome = reconciledPullRequestOutcome(metadata);\n if (\n workItemPhaseSemantics(options.boards, item)?.kind === 'terminal' &&\n reconciledOutcome !== undefined &&\n reconciliation === reconciledOutcome\n ) {\n continue;\n }\n const cards = cardsByNumber.get(pullRequestNumber) ?? [];\n cards.push(item);\n cardsByNumber.set(pullRequestNumber, cards);\n }\n }\n } catch (error) {\n recordFailure(repository, error);\n continue;\n }\n const authorTrust = sweepTrustLookup(options.github, repository);\n for (const { item, author } of unanswered) {\n try {\n await options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { authorTrusted: await authorTrust(author) } },\n });\n } catch (error) {\n recordFailure(repository, error);\n }\n }\n for (const [pullRequestNumber, cards] of cardsByNumber) {\n try {\n const state = await fetchPullRequest({\n installationId: repository.installationId,\n repository: repository.fullName,\n number: pullRequestNumber,\n });\n summary.checked += 1;\n if (!state) continue;\n // Re-stamped on every sweep so revoked write access reads untrusted\n // within one cycle; a failed lookup keeps the last stamp and retries.\n let authorTrusted: boolean | undefined;\n if (state.author !== undefined) {\n try {\n authorTrusted = await authorTrust(state.author);\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n for (const card of cards) {\n if (state.state === 'closed') continue;\n const metadata = card.metadata ?? {};\n const statusChanged =\n metadata.state !== state.state || metadata.draft !== state.draft || metadata.merged !== state.merged;\n const authorChanged = state.author !== undefined && metadata.author !== state.author;\n const assigneesChanged = !sameStrings(metadata.assignees, state.assignees);\n const reviewersChanged = !sameStrings(metadata.requestedReviewers, state.requestedReviewers);\n const labelsChanged = !sameStrings(metadata.labels, state.labels);\n const trustStale = authorTrusted !== undefined && metadata.authorTrusted !== authorTrusted;\n const metadataChanged =\n statusChanged || authorChanged || assigneesChanged || reviewersChanged || labelsChanged || trustStale;\n const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];\n if (!metadataChanged && reconciliation !== 'merged' && reconciliation !== 'closed') continue;\n try {\n await options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: {\n metadata: reconciledPullRequestMetadata(state, 'clear', trustStale ? authorTrusted : undefined),\n },\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n if (state.state !== 'closed') continue;\n const cleanupFailures = new Set<string>();\n for (const card of cards) {\n if (workItemPhaseSemantics(options.boards, card)?.kind !== 'terminal') continue;\n try {\n await options.storage.supersedeDecisionsForWorkItem({\n orgId: card.orgId,\n factoryProjectId: card.factoryProjectId,\n workItemId: card.id,\n supersededAt: new Date(),\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n cleanupFailures.add(card.id);\n }\n }\n await rules.ingest(reconciledClosedEvent(repository, pullRequestNumber, state));\n await retireReconciledSubscriptions(options.integrationStorage, repository, pullRequestNumber, state.merged);\n for (const card of cards) {\n if (cleanupFailures.has(card.id)) continue;\n const trustStale = authorTrusted !== undefined && (card.metadata ?? {}).authorTrusted !== authorTrusted;\n try {\n await options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: {\n metadata: reconciledPullRequestMetadata(state, 'settled', trustStale ? authorTrusted : undefined),\n },\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n if (state.merged) summary.merged += 1;\n else summary.closed += 1;\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n }\n return summary;\n };\n}\n\nexport function githubRulesOptions(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n): GithubRulesOptions | undefined {\n if (!context.runtime) return undefined;\n return {\n github,\n sourceControl: context.storage.sourceControl,\n integrationStorage: context.storage.generic,\n projects: context.storage.projects,\n storage: context.runtime.workItems,\n configVersion: context.runtime.configVersion,\n boards: context.runtime.boards,\n intake: context.storage.intake,\n ...(context.hooks?.onRepositoryPush ? { onRepositoryPush: context.hooks.onRepositoryPush } : {}),\n };\n}\n\nexport function attachGithubRules(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n): ((event: ParsedGithubWebhook) => Promise<unknown>) | undefined {\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n const rules = new GithubRules(options);\n return event => rules.ingest(event);\n}\n\nexport function attachGithubReconciler(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n fetchPullRequest: GithubPullRequestFetcher,\n): GithubPullRequestReconciler | undefined {\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n return createGithubPullRequestReconciler(options, fetchPullRequest);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"rules.js","names":[],"sources":["../../../src/integrations/github/rules.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\n\nimport {\n boardEventHandlers,\n boardForWorkItem,\n eventBoardId,\n rulePhaseField,\n withBoardClosure,\n workItemPhaseSemantics,\n} from '../../boards/index.js';\nimport type { BoardRegistry } from '../../boards/index.js';\nimport { cardLabels, moveCardToBoard } from '../../boards/relocate.js';\nimport { selectEventRule } from '../../rules/event-rules.js';\nimport type {\n FactoryGithubEventName,\n FactoryGithubRuleContext,\n FactoryRuleActor,\n FactoryRuleDecision,\n} from '../../rules/types.js';\nimport { assertFactoryDecisionTarget, validateFactoryRuleDecisions } from '../../rules/validation.js';\nimport { resolveIntakeLabelRoute } from '../../storage/domains/intake/base.js';\nimport type { IntakeStorage } from '../../storage/domains/intake/base.js';\nimport type { IntegrationStorageHandle } from '../../storage/domains/integrations/base.js';\nimport type { FactoryProjectsStorage } from '../../storage/domains/projects/base.js';\nimport type {\n ExternalRepositoryProjectTarget,\n SourceControlStorageHandle,\n} from '../../storage/domains/source-control/base.js';\nimport type { WorkItemRow, WorkItemsStorage } from '../../storage/domains/work-items/base.js';\nimport {\n FACTORY_PULL_REQUEST_RECONCILIATION_KEY,\n WorkItemUpdateConflictError,\n} from '../../storage/domains/work-items/base.js';\nimport type { IntegrationContext, IntegrationHooks } from '../base.js';\nimport { recordPullRequestHead } from '../pull-request-head.js';\nimport type { GithubAppIdentity } from './app-identity.js';\nimport type { GithubEventRules } from './default-rules.js';\nimport type { GithubRepositoryPermission } from './integration.js';\nimport { changeRequestTargetKey } from './subscriptions.js';\nimport type { ParsedGithubWebhook } from './webhook.js';\n\nconst TRUSTED_PERMISSIONS = new Set(['write', 'admin']);\nconst RULE_TIMEOUT_MS = 5_000;\nconst FACTORY_TRIAGE_COMMENT_MARKER = '<!-- mastra-factory-triage -->';\n\nasync function withRuleTimeout<T>(promise: Promise<T>): Promise<T> {\n let timeout: ReturnType<typeof setTimeout> | undefined;\n try {\n return await Promise.race([\n promise,\n new Promise<never>((_, reject) => {\n timeout = setTimeout(() => reject(new Error('FACTORY_RULE_TIMEOUT')), RULE_TIMEOUT_MS);\n }),\n ]);\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\nfunction object(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : undefined;\n}\n\nfunction timestamp(value: unknown): number | undefined {\n const parsed = typeof value === 'string' ? Date.parse(value) : NaN;\n return Number.isNaN(parsed) ? undefined : parsed;\n}\n\nfunction string(value: unknown): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction number(value: unknown): number | undefined {\n return typeof value === 'number' && Number.isFinite(value) ? value : undefined;\n}\n\nfunction boolean(value: unknown): boolean | undefined {\n return typeof value === 'boolean' ? value : undefined;\n}\n\nfunction actorLogins(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(actor => {\n const login = string(object(actor)?.login);\n return login ? [login] : [];\n });\n}\n\nfunction sameLabels(a: readonly string[], b: readonly string[]): boolean {\n return a.length === b.length && a.every((label, index) => label === b[index]);\n}\n\nfunction labelNames(value: unknown): string[] {\n if (!Array.isArray(value)) return [];\n return value.flatMap(label => {\n if (typeof label === 'string') return label ? [label] : [];\n const name = string(object(label)?.name);\n return name ? [name] : [];\n });\n}\n\nfunction parseFactoryReviewCommand(\n body: string | undefined,\n target: string | undefined,\n): { command: 'review' | 're-review'; target: string } | undefined {\n if (!body || !target) return undefined;\n const firstLine = body\n .split('\\n')\n .map(line => line.trim())\n .find(line => line.length > 0)\n ?.toLowerCase();\n if (!firstLine) return undefined;\n const mention = `@${target.toLowerCase().replace(/\\[bot\\]$/, '')}`;\n if (firstLine === `${mention} review`) return { command: 'review', target };\n if (firstLine === `${mention} re-review`) return { command: 're-review', target };\n return undefined;\n}\n\nfunction eventName(parsed: ParsedGithubWebhook): FactoryGithubEventName | undefined {\n const action = string(parsed.payload.action);\n if (parsed.event === 'issues' && action === 'opened') return 'issueOpened';\n if (parsed.event === 'issues' && action === 'edited') {\n const changes = object(parsed.payload.changes);\n return object(changes?.title) || object(changes?.body) ? 'issueEdited' : undefined;\n }\n if (parsed.event === 'issues' && action === 'closed') return 'issueClosed';\n if (parsed.event === 'issue_comment') {\n const issue = object(parsed.payload.issue);\n // A comment on a PR arrives as `issue_comment` with `issue.pull_request` set.\n // It routes to the PR's own event so it binds to the authoring Work item via\n // provenance instead of being mistaken for a comment on an issue of the same\n // number. Only `created` matters: edits and deletions of an existing comment\n // are not new feedback to act on.\n if (object(issue?.pull_request)) {\n return action === 'created' ? 'pullRequestCommentCreated' : undefined;\n }\n if (action === 'created') return 'issueCommentCreated';\n if (action === 'edited') return 'issueCommentEdited';\n if (action === 'deleted') return 'issueCommentDeleted';\n }\n if (parsed.event === 'pull_request' && action === 'opened') return 'pullRequestOpened';\n if (parsed.event === 'pull_request' && action === 'synchronize') return 'pullRequestUpdated';\n if (parsed.event === 'pull_request' && action === 'closed') {\n return boolean(object(parsed.payload.pull_request)?.merged) ? 'pullRequestMerged' : 'pullRequestClosed';\n }\n if (parsed.event === 'pull_request' && action === 'review_requested') return 'pullRequestReviewRequested';\n if (parsed.event === 'pull_request_review' && action === 'submitted') return 'pullRequestReviewSubmitted';\n return undefined;\n}\n\n/**\n * Canonical source keys (`github-issue:N`, `github-pr:N`) do not identify a\n * repository, so a project linked to several repositories could bind repo A's\n * event to repo B's same-numbered card. The card's intake-stamped URL is\n * authoritative; the intake-stamped `githubRepositoryId` covers URL-less\n * cards. A card with neither signal cannot be attributed by number alone.\n */\nconst MAX_STALE_RULE_ATTEMPTS = 3;\n\nexport function cardBelongsToRepository(item: WorkItemRow, repositoryId: number, repositoryFullName: string): boolean {\n const url = item.externalSource?.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/(?:issues|pull)\\/\\d+(?:[/?#]|$)/.exec(url);\n if (match && match[1] === repositoryFullName) return true;\n }\n // A renamed repository leaves the old owner/name in the card URL, so a URL\n // mismatch still defers to the stable intake-stamped repository id.\n return item.metadata?.githubRepositoryId === repositoryId;\n}\n\nfunction canonicalSourceKey(kind: 'issue' | 'pull-request', itemNumber: number): string {\n return kind === 'issue' ? `github-issue:${itemNumber}` : `github-pr:${itemNumber}`;\n}\n\nfunction legacySourceKey(repositoryId: number, kind: 'issue' | 'pull-request', itemNumber: number): string {\n return `github:${repositoryId}:${kind}:${itemNumber}`;\n}\n\nfunction provenanceTarget(repositoryId: number, pullRequestNumber: number): string {\n return `factory-pr-provenance:${repositoryId}:${pullRequestNumber}`;\n}\n\nfunction workItemSource(item: WorkItemRow) {\n if (!item.externalSource) return 'manual' as const;\n return item.externalSource.type === 'pull-request' ? ('github-pr' as const) : ('github-issue' as const);\n}\n\nfunction workItemSourceKey(item: WorkItemRow): string | null {\n return item.externalSource?.externalId ?? null;\n}\n\n// Throws on a failed lookup: callers writing permanent state must retry, not\n// record the failure as distrust.\nexport async function trustedCollaborator(\n github: GithubRulesIntegration,\n input: { installationId: number; repository: string; login: string },\n): Promise<boolean> {\n const permission = await github.getRepositoryCollaboratorPermission(\n input.installationId,\n input.repository,\n input.login,\n );\n return permission !== undefined && TRUSTED_PERMISSIONS.has(permission);\n}\n\n// Terminal cards leave the reconcile loop below, so the ones that got there before author\n// trust was recorded have no other path to an answer.\nfunction authorAwaitingTrust(item: WorkItemRow, repository: ReconcileRepository): string | undefined {\n const metadata = item.metadata ?? {};\n if (typeof metadata.author !== 'string' || metadata.authorTrusted !== undefined) return undefined;\n const tracked = reconcilablePullRequestNumber(item, repository) ?? reconcilableIssueNumber(item, repository);\n if (tracked === undefined) return undefined;\n // A canonical key with no URL names no repository, and the pull request matcher takes it anyway.\n // Asking GitHub about the wrong repository of a multi-repository project would record a wrong answer.\n const unattributed =\n !item.externalSource?.url && /^github-(?:pr|issue):\\d+$/.test(item.externalSource?.externalId ?? '');\n if (unattributed && metadata.githubRepositoryId !== repository.id) return undefined;\n return metadata.author;\n}\n\nexport function sweepTrustLookup(\n github: GithubRulesIntegration,\n repository: ReconcileRepository,\n): (login: string) => Promise<boolean> {\n const cache = new Map<string, boolean>();\n return async login => {\n const cached = cache.get(login);\n if (cached !== undefined) return cached;\n const trusted = await trustedCollaborator(github, {\n installationId: repository.installationId,\n repository: repository.fullName,\n login,\n });\n cache.set(login, trusted);\n return trusted;\n };\n}\n\nasync function githubActor(\n github: GithubRulesIntegration,\n input: { installationId: number; repository: string; login: string; factoryAuthored: boolean },\n): Promise<FactoryRuleActor> {\n // The actor bit is recomputed on every event, so a failed lookup can read\n // untrusted for this one delivery instead of failing the ingest.\n const trusted = await trustedCollaborator(github, input).catch(() => false);\n return { type: 'github', login: input.login, trusted, factoryAuthored: input.factoryAuthored };\n}\n\ninterface FactoryPullRequestProvenanceData {\n kind: 'factory-pr-provenance';\n workItemId: string;\n}\n\nfunction pullRequestProvenance(\n data: Record<string, unknown> | undefined,\n factoryProjectId: string,\n): FactoryPullRequestProvenanceData | null {\n if (!data || data.kind !== 'factory-pr-provenance' || typeof data.workItemId !== 'string') return null;\n // Provenance proves which Factory *project's* run authored the PR. A row\n // written by a sibling project in the same org — or a legacy row without the\n // project stamp — fails closed here: honoring it would brand the PR\n // Factory-authored in a project that never touched it, and auto-start a\n // review that checks out and executes the PR there.\n if (data.factoryProjectId !== factoryProjectId) return null;\n return { kind: 'factory-pr-provenance', workItemId: data.workItemId };\n}\n\nexport interface GithubRulesIntegration {\n readonly rules: GithubEventRules;\n readonly slug?: string;\n /**\n * Factory's own GitHub login, used to ignore its own writes. Optional because\n * not every integration can name itself; when absent, self-recognition falls\n * back to the configured slug and, failing that, to content Factory stamps\n * itself (see `FACTORY_TRIAGE_COMMENT_MARKER`).\n */\n readonly identity?: GithubAppIdentity;\n getRepositoryCollaboratorPermission(\n installationId: number,\n repoFullName: string,\n username: string,\n ): Promise<GithubRepositoryPermission | undefined>;\n}\n\nexport interface GithubRulesOptions {\n github: GithubRulesIntegration;\n sourceControl: SourceControlStorageHandle;\n /** Integration-scoped storage; provenance rows are validated at read. */\n integrationStorage: IntegrationStorageHandle;\n projects: FactoryProjectsStorage;\n storage: WorkItemsStorage;\n configVersion: string;\n boards: BoardRegistry;\n /**\n * Decides which installed board an issue lands on: a label route first, then the repository's\n * intake source binding. Absent means Work.\n */\n intake?: Pick<IntakeStorage, 'listLabelRoutes' | 'listBindings'>;\n /** Hands a push to a linked repository off for an environment build. */\n onRepositoryPush?: IntegrationHooks['onRepositoryPush'];\n}\n\n/** Identity under which label-driven relocations are recorded. */\nconst LABEL_ROUTE_USER_ID = 'factory-rule-dispatcher';\n\ntype IssueActionHandler = (\n parsed: ParsedGithubWebhook,\n repositoryId: number,\n repositoryName: string,\n project: ExternalRepositoryProjectTarget,\n) => Promise<{ status: 'ignored' | 'committed' }>;\n\n/**\n * Whether a login is Factory itself. Prefers the resolved identity, which is\n * observed from Factory's own writes, and falls back to the configured slug.\n */\nexport function isFactoryGithubLogin(\n github: Pick<GithubRulesIntegration, 'identity' | 'slug'>,\n login: string | null | undefined,\n): boolean {\n if (github.identity?.known) return github.identity.matches(login);\n const slug = github.slug?.trim();\n if (!slug || !login) return false;\n return login.toLowerCase() === `${slug.toLowerCase()}[bot]`;\n}\n\nexport class GithubRules {\n constructor(private readonly options: GithubRulesOptions) {}\n\n /**\n * Whether a login is Factory itself. Prefers the resolved identity, which is\n * observed from Factory's own writes, and falls back to the configured slug.\n * An unset slug must not silently answer \"not Factory\" — that is what\n * disabled every self-loop guard.\n */\n #isFactoryLogin(login: string | undefined): boolean {\n return isFactoryGithubLogin(this.options.github, login);\n }\n\n #factoryMentionTarget(): string | undefined {\n const identity = this.options.github.identity;\n if (identity?.known) return identity.login;\n const slug = this.options.github.slug?.trim();\n return slug ? `${slug.toLowerCase()}[bot]` : undefined;\n }\n\n /**\n * Board an issue lands on: the one its labels select under the project's label routes, else the\n * board the repository's intake source binding names. Only installed boards count. Undefined\n * leaves built-in routing (Work) in charge.\n */\n async #intakeTarget(\n project: ExternalRepositoryProjectTarget,\n repositoryName: string,\n labels: readonly string[],\n ): Promise<{ board: string; initialPhase: string } | undefined> {\n const intake = this.options.intake;\n if (!intake) return undefined;\n const { orgId, factoryProjectId } = project;\n if (labels.length > 0) {\n const routes = await intake.listLabelRoutes({ orgId, factoryProjectId, integrationId: 'github' });\n const route = resolveIntakeLabelRoute(routes, labels);\n const board = route ? this.options.boards.get(route.board) : undefined;\n if (board) return { board: board.id, initialPhase: board.initialPhase };\n }\n // GitHub bindings are keyed by the internal repository id; the slug is accepted too since the\n // bindings API stores whatever source id it is given.\n const slug = repositoryName.toLowerCase();\n const binding = (await intake.listBindings({ orgId, integrationId: 'github' })).find(\n candidate =>\n candidate.factoryProjectId === factoryProjectId &&\n (candidate.sourceId === project.projectRepository.repositoryId || candidate.sourceId.toLowerCase() === slug),\n );\n const board = binding?.board ? this.options.boards.get(binding.board) : undefined;\n return board ? { board: board.id, initialPhase: board.initialPhase } : undefined;\n }\n\n /**\n * `labeled` / `unlabeled` are not rule events: the labels only decide which board the card belongs\n * on, so the card is re-routed here and its label metadata refreshed. Cards a run owns, and\n * finished cards, stay where they are.\n */\n async #relocateLabeledIssue(\n parsed: ParsedGithubWebhook,\n repositoryId: number,\n repositoryName: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'ignored' | 'committed' }> {\n const issue = object(parsed.payload.issue);\n const issueNumber = issue?.pull_request === undefined ? number(issue?.number) : undefined;\n if (!issueNumber) return { status: 'ignored' };\n const found = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n issueNumber,\n undefined,\n undefined,\n null,\n );\n if (!found || found.externalSource?.type !== 'issue') return { status: 'ignored' };\n const labels = labelNames(issue?.labels);\n let item = found;\n let changed = false;\n if (!sameLabels(cardLabels(item), labels)) {\n let updated;\n try {\n updated = await this.options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: LABEL_ROUTE_USER_ID,\n patch: { metadata: { ...(item.metadata ?? {}), labels } },\n expectedRevision: item.revision,\n });\n } catch (error) {\n // The card changed under us (a run wrote it, or a concurrent delivery won). The next\n // delivery or reconcile pass carries the same labels, so drop this one instead of 5xx-ing.\n if (!(error instanceof WorkItemUpdateConflictError)) throw error;\n return { status: 'ignored' };\n }\n if (!updated) return { status: 'ignored' };\n item = updated.item;\n changed = true;\n }\n const target = await this.#intakeTarget(project, repositoryName, labels);\n const outcome = await moveCardToBoard({\n workItems: this.options.storage,\n boardRegistry: this.options.boards,\n userId: LABEL_ROUTE_USER_ID,\n item,\n targetBoard: target?.board ?? 'work',\n });\n return { status: changed || outcome === 'moved' ? 'committed' : 'ignored' };\n }\n\n /**\n * `assigned` / `unassigned` are not rule events either: an existing issue card only mirrors the\n * issue's full assignee list. No card is created, moved, or handed to a run.\n */\n async #syncIssueAssignees(\n parsed: ParsedGithubWebhook,\n repositoryId: number,\n repositoryName: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'ignored' | 'committed' }> {\n const issue = object(parsed.payload.issue);\n const issueNumber = issue?.pull_request === undefined ? number(issue?.number) : undefined;\n if (!issueNumber) return { status: 'ignored' };\n const item = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n issueNumber,\n undefined,\n undefined,\n null,\n );\n if (!item || item.externalSource?.type !== 'issue') return { status: 'ignored' };\n const assignees = actorLogins(issue?.assignees);\n // GitHub can deliver webhooks out of order; drop payloads older than the last applied one.\n // Timestamps have one-second resolution, so equal timestamps still apply.\n const updatedAt = string(issue?.updated_at);\n const payloadTime = timestamp(updatedAt);\n const storedTime = timestamp(item.metadata?.githubAssigneesUpdatedAt);\n if (payloadTime !== undefined && storedTime !== undefined && payloadTime < storedTime) {\n return { status: 'ignored' };\n }\n // A newer payload with unchanged assignees still advances the stored time, so a delayed older\n // payload cannot slip in behind it.\n const advancesTime = payloadTime !== undefined && (storedTime === undefined || payloadTime > storedTime);\n if (sameStrings(item.metadata?.assignees, assignees) && !advancesTime) return { status: 'ignored' };\n try {\n const updated = await this.options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: LABEL_ROUTE_USER_ID,\n patch: {\n metadata: {\n ...(item.metadata ?? {}),\n assignees,\n ...(payloadTime !== undefined ? { githubAssigneesUpdatedAt: updatedAt } : {}),\n },\n },\n expectedRevision: item.revision,\n });\n return { status: updated ? 'committed' : 'ignored' };\n } catch (error) {\n // A concurrent write won; nothing reconciles issue-card assignees, so they stay as the\n // winner left them until the next assigned/unassigned delivery for this issue.\n if (!(error instanceof WorkItemUpdateConflictError)) throw error;\n return { status: 'ignored' };\n }\n }\n\n /** `issues` actions that are not rule events but still update an existing card. */\n #issueActionHandler(parsed: ParsedGithubWebhook): IssueActionHandler | undefined {\n if (parsed.event !== 'issues') return undefined;\n switch (string(parsed.payload.action)) {\n case 'labeled':\n case 'unlabeled':\n return (...args) => this.#relocateLabeledIssue(...args);\n case 'assigned':\n case 'unassigned':\n return (...args) => this.#syncIssueAssignees(...args);\n default:\n return undefined;\n }\n }\n\n async ingest(parsed: ParsedGithubWebhook): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> {\n const event = eventName(parsed);\n const repository = object(parsed.payload.repository);\n const installationId = number(object(parsed.payload.installation)?.id);\n const repositoryId = number(repository?.id);\n const repositoryName = string(repository?.full_name);\n const login = string(object(parsed.payload.sender)?.login);\n if (parsed.event === 'push' && installationId && repositoryId) {\n await this.#handOffPush(parsed, installationId, repositoryId);\n return { status: 'ignored' };\n }\n if (!installationId || !repositoryId || !repositoryName || !login) return { status: 'ignored' };\n const issueAction = this.#issueActionHandler(parsed);\n const handle = event\n ? (project: ExternalRepositoryProjectTarget) =>\n this.#ingestProject(parsed, event, installationId, repositoryId, repositoryName, login, project)\n : issueAction\n ? (project: ExternalRepositoryProjectTarget) => issueAction(parsed, repositoryId, repositoryName, project)\n : undefined;\n if (!handle) return { status: 'ignored' };\n\n const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(installationId),\n repositoryExternalId: String(repositoryId),\n });\n if (projects.length === 0) return { status: 'ignored' };\n const results = [];\n for (const project of projects) {\n results.push(await handle(project));\n }\n if (results.some(result => result.status === 'committed')) return { status: 'committed' };\n if (results.some(result => result.status === 'replayed')) return { status: 'replayed' };\n return results[0] ?? { status: 'ignored' };\n }\n\n /**\n * A push is not a work-item event; it only reaches the environment build\n * hand-off, once per project the repository is linked to. The hook decides\n * whether the project builds on push.\n */\n async #handOffPush(parsed: ParsedGithubWebhook, installationId: number, repositoryId: number): Promise<void> {\n const onRepositoryPush = this.options.onRepositoryPush;\n const ref = string(parsed.payload.ref);\n const defaultBranch = string(object(parsed.payload.repository)?.default_branch);\n if (!onRepositoryPush || !ref || !defaultBranch) return;\n const projects = await this.options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(installationId),\n repositoryExternalId: String(repositoryId),\n });\n for (const project of projects) {\n onRepositoryPush({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n projectRepository: {\n id: project.projectRepository.id,\n inEnvironment: project.projectRepository.inEnvironment,\n },\n ref,\n defaultBranch,\n });\n }\n }\n\n async #ingestProject(\n parsed: ParsedGithubWebhook,\n event: FactoryGithubEventName,\n installationId: number,\n repositoryId: number,\n repositoryName: string,\n login: string,\n project: ExternalRepositoryProjectTarget,\n ): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> {\n const factoryProject = await this.options.projects.get({\n orgId: project.orgId,\n id: project.factoryProjectId,\n });\n if (!factoryProject) return { status: 'missing' };\n const issue = object(parsed.payload.issue);\n const issueComment = object(parsed.payload.comment);\n const changes = object(parsed.payload.changes);\n // A comment on a PR carries the PR under `issue` (with `pull_request` set)\n // and has no `pull_request` payload of its own. Read the PR from `issue` in\n // that case so provenance and `context.pullRequest` behave as they do for\n // every other PR event, and so the number is never treated as an issue's.\n const commentOnPullRequest = object(parsed.payload.issue)?.pull_request !== undefined;\n const pullRequest = object(parsed.payload.pull_request) ?? (commentOnPullRequest ? issue : undefined);\n const issueNumber = commentOnPullRequest ? undefined : number(issue?.number);\n const pullRequestNumber = number(pullRequest?.number);\n const provenance = pullRequestNumber\n ? pullRequestProvenance(\n (\n await this.options.integrationStorage.subscriptions.listByTarget(\n provenanceTarget(repositoryId, pullRequestNumber),\n { status: 'active' },\n )\n ).find(\n subscription =>\n subscription.orgId === project.orgId && subscription.data?.factoryProjectId === project.factoryProjectId,\n )?.data,\n project.factoryProjectId,\n )\n : null;\n // Re-review events target the PR's own Review card, not the Work item that\n // provenance would otherwise bind the event to. For review_requested the\n // sender is whoever clicked re-request, so a Factory-authored PR must not\n // brand a human requester as factory-authored.\n const reviewRequested = event === 'pullRequestReviewRequested';\n const reviewCommand =\n event === 'pullRequestCommentCreated'\n ? parseFactoryReviewCommand(string(issueComment?.body), this.#factoryMentionTarget())\n : undefined;\n const reviewEntryRequested = reviewRequested || reviewCommand !== undefined;\n // Provenance proves the *pull request* came from Factory, which is not the\n // same as the sender of this event. For events where the sender is whoever\n // reacted to the PR — re-requesting review, commenting, submitting a review\n // — branding them from provenance would mark every human and every review\n // bot as Factory. Only the app login identifies Factory for those.\n const senderIsResponder =\n reviewRequested || event === 'pullRequestCommentCreated' || event === 'pullRequestReviewSubmitted';\n const reReviewEvent = reviewEntryRequested || event === 'pullRequestUpdated';\n const requestedReviewer = string(object(parsed.payload.requested_reviewer)?.login);\n const pullRequestAuthor = string(object(pullRequest?.user)?.login);\n const pullRequestFactoryAuthored = provenance !== null || this.#isFactoryLogin(pullRequestAuthor);\n const resolvedItem = await this.#relatedItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n issueNumber,\n pullRequestNumber,\n string(object(pullRequest?.head)?.ref),\n reReviewEvent ? null : provenance,\n senderIsResponder && !reviewEntryRequested,\n );\n // A review-entry request must never treat a branch-matched authoring Work\n // card as the PR's Review card. A missing Review card is materialized below.\n const relatedItem =\n reviewEntryRequested && resolvedItem?.externalSource?.type !== 'pull-request' ? undefined : resolvedItem;\n const intake = issueNumber\n ? await this.#intakeTarget(project, repositoryName, labelNames(issue?.labels))\n : undefined;\n const actor = await githubActor(this.options.github, {\n installationId,\n repository: repositoryName,\n login,\n factoryAuthored: (!senderIsResponder && provenance !== null) || this.#isFactoryLogin(login),\n });\n // A marked handoff comment is ignored only when Factory authored it: a\n // human may quote the marker to add an investigation lead, and that must\n // still retrigger triage. Recognising the author is therefore the whole\n // guard — when identity cannot be resolved this fails open and Factory's\n // own handoff cancels the run that wrote it.\n if (\n actor.type === 'github' &&\n actor.factoryAuthored &&\n (event === 'issueCommentCreated' || event === 'issueCommentEdited') &&\n string(issueComment?.body)?.includes(FACTORY_TRIAGE_COMMENT_MARKER)\n ) {\n return { status: 'ignored' };\n }\n // One delivery can concern two cards — a merged pull request settles both\n // its own Review card and the Work item that authored it — and every\n // decision a rule returns is committed against a single item, at that\n // item's revision. So the evaluation, not the decision, is what fans out:\n // the rule runs once per bound item, each with its own ingress identity.\n const evaluate = async (\n item: WorkItemRow | undefined,\n ingressIdentity: string,\n /** Set on the evaluation that files the pull request's own Review card. */\n pullRequestIntake = false,\n attempt = 1,\n ): Promise<{ status: 'ignored' | 'committed' | 'replayed' | 'missing' }> => {\n const context: FactoryGithubRuleContext = {\n tenant: { orgId: project.orgId, projectId: project.factoryProjectId },\n actor,\n ingress: { type: 'github', id: ingressIdentity },\n cause: `github.${event}`,\n causalChain: [],\n configVersion: this.options.configVersion,\n ...(item\n ? {\n item: {\n id: item.id,\n source: workItemSource(item),\n sourceKey: workItemSourceKey(item),\n parentWorkItemId: item.parentWorkItemId,\n title: item.title,\n url: item.externalSource?.url ?? null,\n stages: item.stages,\n acceptedAt: item.acceptedAt,\n metadata: item.metadata,\n },\n board: boardForWorkItem(item),\n itemRevision: item.revision,\n ...withBoardClosure(this.options.boards, item),\n ...rulePhaseField(this.options.boards, item),\n }\n : {}),\n ...(intake ? { intake } : {}),\n ...(pullRequestIntake ? { pullRequestIntake: true } : {}),\n event,\n deliveryId: parsed.deliveryId,\n factory: { createdAt: factoryProject.createdAt.toISOString() },\n repository: { id: repositoryId, fullName: repositoryName, installationId },\n ...(issueNumber && string(issue?.title) && string(issue?.html_url)\n ? {\n issue: {\n number: issueNumber,\n title: string(issue?.title)!,\n url: string(issue?.html_url)!,\n ...(string(issue?.created_at) ? { createdAt: string(issue?.created_at) } : {}),\n ...(string(issue?.updated_at) ? { updatedAt: string(issue?.updated_at) } : {}),\n assignees: actorLogins(issue?.assignees),\n labels: labelNames(issue?.labels),\n ...(string(issue?.state) === 'closed' || string(issue?.state) === 'open'\n ? { state: string(issue?.state) as 'open' | 'closed' }\n : {}),\n ...(string(issue?.state_reason) ? { stateReason: string(issue?.state_reason) } : {}),\n },\n }\n : {}),\n ...(event === 'issueEdited'\n ? { issueChange: { title: Boolean(object(changes?.title)), body: Boolean(object(changes?.body)) } }\n : {}),\n ...(number(issueComment?.id)\n ? {\n issueComment: {\n id: number(issueComment?.id)!,\n ...(string(issueComment?.body) ? { body: string(issueComment?.body) } : {}),\n ...(string(issueComment?.html_url) ? { url: string(issueComment?.html_url) } : {}),\n ...(string(object(issueComment?.user)?.login)\n ? { author: string(object(issueComment?.user)?.login) }\n : {}),\n ...(string(object(issueComment?.user)?.type)\n ? { authorType: string(object(issueComment?.user)?.type) }\n : {}),\n ...(string(issueComment?.created_at) ? { createdAt: string(issueComment?.created_at) } : {}),\n ...(string(issueComment?.updated_at) ? { updatedAt: string(issueComment?.updated_at) } : {}),\n },\n }\n : {}),\n ...(pullRequestNumber && string(pullRequest?.title) && string(pullRequest?.html_url)\n ? {\n pullRequest: {\n number: pullRequestNumber,\n title: string(pullRequest?.title)!,\n url: string(pullRequest?.html_url)!,\n ...(string(pullRequest?.created_at) ? { createdAt: string(pullRequest?.created_at) } : {}),\n state: string(pullRequest?.state) === 'closed' ? ('closed' as const) : ('open' as const),\n draft: boolean(pullRequest?.draft) ?? false,\n merged: boolean(pullRequest?.merged) ?? false,\n assignees: actorLogins(pullRequest?.assignees),\n requestedReviewers: actorLogins(pullRequest?.requested_reviewers),\n labels: labelNames(pullRequest?.labels),\n ...(pullRequestAuthor ? { author: pullRequestAuthor } : {}),\n factoryAuthored: pullRequestFactoryAuthored,\n headBranch: string(object(pullRequest?.head)?.ref) ?? '',\n baseBranch: string(object(pullRequest?.base)?.ref) ?? '',\n },\n }\n : {}),\n ...(reviewRequested && requestedReviewer\n ? {\n reviewRequest: {\n reviewer: requestedReviewer,\n factoryReviewer: this.#isFactoryLogin(requestedReviewer),\n },\n }\n : {}),\n ...(reviewCommand ? { reviewCommand } : {}),\n ...(object(parsed.payload.review)\n ? {\n review: {\n id: number(object(parsed.payload.review)?.id) ?? 0,\n state: string(object(parsed.payload.review)?.state) ?? 'unknown',\n url: string(object(parsed.payload.review)?.html_url) ?? '',\n ...(string(object(object(parsed.payload.review)?.user)?.login)\n ? { author: string(object(object(parsed.payload.review)?.user)?.login) }\n : {}),\n ...(string(object(parsed.payload.review)?.body)\n ? { body: string(object(parsed.payload.review)?.body) }\n : {}),\n },\n }\n : {}),\n };\n\n const rule = selectEventRule(\n this.options.github.rules,\n boardEventHandlers(this.options.boards, eventBoardId(context), 'github'),\n event,\n );\n let decision: FactoryRuleDecision | void;\n let decisions: Record<string, unknown>[] = [];\n let outcome: { status: 'accepted' | 'rejected'; code?: string; reason?: string } = { status: 'accepted' };\n try {\n decision = rule ? await withRuleTimeout(Promise.resolve(rule(Object.freeze(context)))) : undefined;\n if (decision?.type === 'reject') {\n outcome = { status: 'rejected', code: decision.code, reason: decision.reason };\n } else if (decision) {\n decisions = validateFactoryRuleDecisions([decision]).map(entry => {\n assertFactoryDecisionTarget(entry, this.options.boards, item ? boardForWorkItem(item) : undefined);\n return { ...entry };\n });\n }\n } catch (error) {\n const timedOut = error instanceof Error && error.message === 'FACTORY_RULE_TIMEOUT';\n outcome = {\n status: 'rejected',\n code: timedOut ? 'timeout' : 'rule_error',\n reason: timedOut\n ? 'Factory rule evaluation timed out.'\n : error instanceof Error\n ? error.message.slice(0, 2_000)\n : 'Factory GitHub rule failed.',\n };\n }\n\n const committed = await this.options.storage.commitRuleEvaluation({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n workItemId: item?.id ?? null,\n ingress: { identity: ingressIdentity, triggerType: `github.${event}` },\n configVersion: this.options.configVersion,\n expectedRevision: item?.revision ?? null,\n actor: { ...actor },\n outcome,\n decisions,\n causalChain: [],\n now: new Date(),\n });\n if (committed.status === 'stale') {\n // The item was written concurrently. Re-read it and run the rule again\n // against the fresh revision; nothing was persisted for this attempt.\n if (attempt >= MAX_STALE_RULE_ATTEMPTS) {\n throw new Error(`Factory GitHub rule evaluation for ${ingressIdentity} kept losing revision races.`);\n }\n const fresh = item ? await this.options.storage.get({ orgId: project.orgId, id: item.id }) : null;\n if (item && !fresh) return { status: 'missing' };\n return evaluate(fresh ?? undefined, ingressIdentity, pullRequestIntake, attempt + 1);\n }\n return { status: committed.status };\n };\n\n // A push moves the head a recorded review verdict was given on. Recording\n // the new head lets the verdict badge show that it is outdated, while the\n // verdict itself stays so the next pass still runs as a re-review. It is\n // recorded before the push is evaluated: the dispatcher can apply the\n // re-review transition as soon as it commits, and the pass it starts names\n // the head it covers, which must be the pushed one.\n const stampHead = async () => {\n const headSha = string(object(pullRequest?.head)?.sha)?.toLowerCase();\n if (event !== 'pullRequestUpdated' || !headSha || !pullRequestNumber) return;\n const headAt = timestamp(pullRequest?.updated_at);\n if (relatedItem?.externalSource?.type !== 'pull-request') return;\n const parent = await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n relatedItem,\n );\n // The authoring Work item mirrors the verdict of the pull request it has\n // out; a push to an older one must not mark its successor's verdict.\n await recordPullRequestHead(this.options.storage, {\n orgId: relatedItem.orgId,\n id: relatedItem.id,\n headSha,\n headAt,\n });\n if (parent) {\n await recordPullRequestHead(this.options.storage, {\n orgId: parent.orgId,\n id: parent.id,\n headSha,\n headAt,\n ownedPullRequestNumber: pullRequestNumber,\n });\n }\n };\n await stampHead();\n const evaluated =\n event === 'pullRequestUpdated' && relatedItem\n ? ((await this.options.storage.get({ orgId: relatedItem.orgId, id: relatedItem.id })) ?? relatedItem)\n : relatedItem;\n const deliveryIdentity = `${installationId}:${parsed.deliveryId}`;\n // A pull request opening concerns two cards: its own Review card, which the\n // arrival rule files — committed against the Work item that authored the\n // pull request when one exists, because that binding is what links the two\n // — and that authoring item, which is now out for review. The arrival is\n // the delivery's own evaluation; the item's is a second one, under an\n // identity suffixed with its id, because ingress identities are the replay\n // key and reusing the delivery's own would drop it as a duplicate.\n const pullRequestOpened = event === 'pullRequestOpened';\n const primary = await evaluate(evaluated, deliveryIdentity, pullRequestOpened);\n // A closed pull request is the one *other* event both linked cards need:\n // the Review card has to close, and the Work item that wrote the code has\n // to finish (on merge) or at least stop recording it as open. Resolution binds the delivery to\n // whichever card it matched first, so evaluate the other one too.\n const linked =\n (event === 'pullRequestMerged' || event === 'pullRequestClosed') && relatedItem && pullRequestNumber\n ? await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n relatedItem,\n )\n : undefined;\n // Moving the card to Done does not touch its pull request fields, so without\n // this the card reads \"open\" until the next sweep and still offers Re-review.\n // Stamped after the evaluations, which commit at the revision they read.\n const stampClosed = async (companionStatus?: string) => {\n if (!pullRequestNumber) return;\n // The authoring Work item records which pull request it has out, so an\n // agent cannot close the work while that pull request is still open.\n if (pullRequestOpened) {\n // Mirrors the out-for-review rule's trust gate. A replayed opened\n // delivery only restores the mark (after a failed write) while the\n // pull request's Review card still records it open, so a redelivery\n // after the close cannot block the Work item again.\n const trusted = (actor.type === 'github' && actor.trusted) || pullRequestFactoryAuthored;\n const reviewCard =\n authoringItem && trusted\n ? await this.#linkedClosureItem(\n project.orgId,\n project.factoryProjectId,\n repositoryId,\n repositoryName,\n pullRequestNumber,\n authoringItem,\n )\n : undefined;\n const stillOpen =\n companionStatus === 'replayed'\n ? reviewCard !== undefined && reviewCard.metadata?.state !== 'closed'\n : reviewCard?.metadata?.state !== 'closed';\n if (authoringItem && trusted && stillOpen) {\n // The head comes along so a head recorded for an earlier pull\n // request cannot mark this one's verdict outdated. A replayed opening\n // of the pull request already recorded keeps the head its pushes left.\n const rebinding = authoringItem.metadata?.openPullRequestNumber !== pullRequestNumber;\n const head = rebinding\n ? {\n pullRequestHeadSha: string(object(pullRequest?.head)?.sha)?.toLowerCase() ?? null,\n pullRequestHeadAt: timestamp(pullRequest?.updated_at) ?? null,\n }\n : {};\n await this.options.storage.update({\n orgId: authoringItem.orgId,\n id: authoringItem.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { openPullRequestNumber: pullRequestNumber, ...head } },\n });\n }\n return;\n }\n if (event !== 'pullRequestMerged' && event !== 'pullRequestClosed') return;\n for (const card of [relatedItem, linked]) {\n if (!card) continue;\n if (card.externalSource?.type !== 'pull-request') {\n // A merge settles the review, so the authoring Work item's mirrored\n // \"request changes\" no longer stops it from being closed.\n // Only the pull request the card has out settles it; an older one\n // merging must not clear a verdict that belongs to its successor.\n const recorded = card.metadata?.openPullRequestNumber;\n const ownsCard = typeof recorded !== 'number' || recorded === pullRequestNumber;\n const settled = {\n ...(ownsCard && event === 'pullRequestMerged' && typeof card.metadata?.reviewVerdict === 'string'\n ? { reviewVerdict: null }\n : {}),\n ...(recorded === pullRequestNumber ? { openPullRequestNumber: null } : {}),\n };\n if (Object.keys(settled).length > 0) {\n await this.options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: settled },\n });\n }\n continue;\n }\n await this.options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { state: 'closed', merged: event === 'pullRequestMerged' } },\n });\n }\n };\n const authoringItem =\n linked === undefined &&\n pullRequestOpened &&\n relatedItem !== undefined &&\n relatedItem.externalSource?.type !== 'pull-request'\n ? relatedItem\n : undefined;\n if (linked === undefined && authoringItem === undefined) {\n await stampClosed();\n return primary;\n }\n const companion = linked ?? authoringItem;\n const secondary = await evaluate(companion, `${deliveryIdentity}:${companion?.id ?? 'pull-request'}`);\n await stampClosed(secondary.status);\n for (const status of ['committed', 'replayed'] as const) {\n if (primary.status === status || secondary.status === status) return { status };\n }\n return primary;\n }\n\n /**\n * The other card a closed pull request concerns, joined through the Review\n * card's `parentWorkItemId` — the link `upsertLinkedWorkItem` records when the\n * pull request is opened, and therefore an exact join that needs no branch\n * heuristics. Returns nothing when the pull request has only one card, which\n * is every pull request Factory did not open from a work item's session.\n */\n async #linkedClosureItem(\n orgId: string,\n projectId: string,\n repositoryId: number,\n repositoryFullName: string,\n pullRequestNumber: number,\n resolved: WorkItemRow,\n ): Promise<WorkItemRow | undefined> {\n const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });\n const linked =\n resolved.externalSource?.type === 'pull-request'\n ? // Bound to the pull request's own Review card: follow the recorded\n // link back to the work item that authored it.\n items.find(item => item.id === resolved.parentWorkItemId)\n : // Bound to the work item (provenance): find the Review card this pull\n // request opened, and only when it names this item as its parent — a\n // card for the same number in another repository is not this one's.\n items.find(\n item =>\n item.parentWorkItemId === resolved.id &&\n (item.externalSource?.externalId === canonicalSourceKey('pull-request', pullRequestNumber) ||\n item.externalSource?.externalId === legacySourceKey(repositoryId, 'pull-request', pullRequestNumber)) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n );\n return linked?.id === resolved.id ? undefined : linked;\n }\n\n async #relatedItem(\n orgId: string,\n projectId: string,\n repositoryId: number,\n repositoryFullName: string,\n issueNumber: number | undefined,\n pullRequestNumber: number | undefined,\n pullRequestHeadBranch: string | undefined,\n provenance: FactoryPullRequestProvenanceData | null,\n preferAuthoringItem = false,\n ): Promise<WorkItemRow | undefined> {\n const items = await this.options.storage.list({ orgId, factoryProjectId: projectId });\n const resolved = this.#resolveItem(\n items,\n repositoryId,\n repositoryFullName,\n issueNumber,\n pullRequestNumber,\n pullRequestHeadBranch,\n provenance,\n );\n // Feedback on a pull request has to reach the item that *wrote* the code.\n // Provenance normally lands it there directly, but when provenance is\n // missing the PR-number lookup wins and returns the PR's own Review card\n // instead — a board the feedback rules deliberately refuse to act on, so\n // the wake is silently dropped. The linked card records its author in\n // `parentWorkItemId`, so follow that link back rather than relaxing the\n // guard, which would let a Review card react to its own posted review.\n if (preferAuthoringItem && resolved?.externalSource?.type === 'pull-request' && resolved.parentWorkItemId) {\n return items.find(item => item.id === resolved.parentWorkItemId) ?? resolved;\n }\n return resolved;\n }\n\n #resolveItem(\n items: WorkItemRow[],\n repositoryId: number,\n repositoryFullName: string,\n issueNumber: number | undefined,\n pullRequestNumber: number | undefined,\n pullRequestHeadBranch: string | undefined,\n provenance: FactoryPullRequestProvenanceData | null,\n ): WorkItemRow | undefined {\n if (provenance) return items.find(item => item.id === provenance.workItemId);\n if (issueNumber) {\n return (\n items.find(\n item =>\n item.externalSource?.externalId === canonicalSourceKey('issue', issueNumber) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n ) ?? items.find(item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'issue', issueNumber))\n );\n }\n if (pullRequestNumber) {\n return (\n items.find(\n item =>\n item.externalSource?.externalId === canonicalSourceKey('pull-request', pullRequestNumber) &&\n cardBelongsToRepository(item, repositoryId, repositoryFullName),\n ) ??\n items.find(\n item => item.externalSource?.externalId === legacySourceKey(repositoryId, 'pull-request', pullRequestNumber),\n ) ??\n // Provenance fallback: a PR pushed from a work item's session branch\n // belongs to that item even when no gh-pr-create provenance was\n // recorded (session predating state seeding, or the PR was opened\n // outside the tracked tool call). Session branches are per-item\n // (`factory/issue-N`), so a head-branch match is unambiguous.\n (pullRequestHeadBranch\n ? items.find(\n item =>\n item.externalSource?.type !== 'pull-request' &&\n Object.values(item.sessions).some(session => session.branch === pullRequestHeadBranch),\n )\n : undefined)\n );\n }\n return undefined;\n }\n}\n\nexport interface ReconcilePullRequestState {\n title: string;\n url: string;\n state: 'open' | 'closed';\n draft: boolean;\n merged: boolean;\n assignees?: string[];\n requestedReviewers?: string[];\n labels?: string[];\n headBranch: string;\n baseBranch: string;\n author?: string;\n createdAt?: string;\n mergedBy?: string;\n}\n\nexport interface PolledPullRequestState extends ReconcilePullRequestState {\n createdAt: string;\n}\n\nexport type GithubPullRequestFetcher = (input: {\n installationId: number;\n repository: string;\n number: number;\n}) => Promise<ReconcilePullRequestState | undefined>;\n\nexport interface ReconcileIssueState {\n title: string;\n url: string;\n state: 'open' | 'closed';\n /** GitHub close reason: `completed`, `not_planned`, or `duplicate`. */\n stateReason?: string;\n assignees?: string[];\n labels?: string[];\n author?: string;\n createdAt?: string;\n updatedAt?: string;\n}\n\nexport type GithubIssueFetcher = (input: {\n installationId: number;\n repository: string;\n number: number;\n}) => Promise<ReconcileIssueState | undefined>;\n\n/** Lists a repository's open issues (pull requests excluded) for missed-open discovery. */\nexport type GithubOpenIssueLister = (input: {\n installationId: number;\n repository: string;\n}) => Promise<Array<ReconcileIssueState & { number: number }>>;\n\nexport interface ReconcileRepository {\n id: number;\n fullName: string;\n installationId: number;\n}\n\nexport interface ReconcileSweepSummary {\n /** Factory-configured repositories included in the sweep. */\n repositories: number;\n /** PRs whose live state was fetched from GitHub. */\n checked: number;\n /** Missed merges replayed through the rules ingress. */\n merged: number;\n /** Missed closes-without-merge replayed through the rules ingress. */\n closed: number;\n /** PRs/issues (or whole repositories) skipped because of an error. */\n failed: number;\n /** Error samples with context, capped at {@link RECONCILE_ERROR_SAMPLE_LIMIT}. */\n errors: Array<{ repository: string; pullRequestNumber?: number; issueNumber?: number; error: string }>;\n}\n\nexport type GithubPullRequestReconciler = (repositories: ReconcileRepository[]) => Promise<ReconcileSweepSummary>;\n\nexport const RECONCILE_ERROR_SAMPLE_LIMIT = 5;\n\nexport function sameStrings(left: unknown, right: string[] | undefined): boolean {\n if (right === undefined) return true;\n if (!Array.isArray(left)) return false;\n const leftValues = new Set(left.flatMap(value => (typeof value === 'string' ? [value] : [])));\n const rightValues = new Set(right);\n return leftValues.size === rightValues.size && [...leftValues].every(value => rightValues.has(value));\n}\n\n/**\n * Extracts the PR number a work item tracks, but only when the item belongs\n * to the given repository. Card URLs pin the repository unambiguously; the\n * legacy source key embeds the repository id. Canonical keys (`github-pr:N`)\n * carry no repository, so they are only trusted when the item has no URL —\n * a project mapped to multiple repositories must not reconcile one repo's\n * card against another repo's PR number.\n */\nfunction reconcilablePullRequestNumber(item: WorkItemRow, repository: ReconcileRepository): number | undefined {\n if (item.externalSource?.type !== 'pull-request') return undefined;\n const url = item.externalSource.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/pull\\/(\\d+)(?:[/?#]|$)/.exec(url);\n if (!match) return undefined;\n return match[1] === repository.fullName ? Number(match[2]) : undefined;\n }\n const externalId = item.externalSource.externalId;\n const legacy = /^github:(\\d+):pull-request:(\\d+)$/.exec(externalId);\n if (legacy) return Number(legacy[1]) === repository.id ? Number(legacy[2]) : undefined;\n const canonical = /^github-pr:(\\d+)$/.exec(externalId);\n return canonical ? Number(canonical[1]) : undefined;\n}\n\n/**\n * Extracts the issue number a work item tracks, but only when the item\n * belongs to the given repository. Stricter than\n * {@link reconcilablePullRequestNumber}: a canonical key with no URL is only\n * trusted when the intake-stamped `githubRepositoryId` confirms the\n * repository, because the sweep initiates closes on its own.\n */\nexport function reconcilableIssueNumber(item: WorkItemRow, repository: ReconcileRepository): number | undefined {\n if (item.externalSource?.type !== 'issue') return undefined;\n const url = item.externalSource.url;\n if (url) {\n const match = /^https?:\\/\\/[^/]+\\/(.+)\\/issues\\/(\\d+)(?:[/?#]|$)/.exec(url);\n if (!match) return undefined;\n // A renamed repository leaves the old owner/name in the card URL, so a\n // URL mismatch still defers to the stable intake-stamped repository id.\n const belongs = match[1] === repository.fullName || item.metadata?.githubRepositoryId === repository.id;\n return belongs ? Number(match[2]) : undefined;\n }\n const externalId = item.externalSource.externalId;\n const legacy = /^github:(\\d+):issue:(\\d+)$/.exec(externalId);\n if (legacy) return Number(legacy[1]) === repository.id ? Number(legacy[2]) : undefined;\n const canonical = /^github-issue:(\\d+)$/.exec(externalId);\n if (!canonical) return undefined;\n // Canonical keys carry no repository; only the intake-stamped repository id\n // can attribute a URL-less card, and guessing would let a multi-repo\n // project close repo B's card because repo A's same-numbered issue closed.\n return item.metadata?.githubRepositoryId === repository.id ? Number(canonical[1]) : undefined;\n}\n\nexport function reconciledIssueClosedEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n return {\n event: 'issues',\n // Stable per (repository, issue): the ingress dedupe makes repeat\n // reconcile cycles replay instead of re-committing decisions.\n deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:closed`,\n payload: {\n action: 'closed',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? 'github' },\n issue: {\n number: issueNumber,\n title: state.title,\n html_url: state.url,\n state: 'closed',\n ...(state.stateReason ? { state_reason: state.stateReason } : {}),\n ...(state.createdAt ? { created_at: state.createdAt } : {}),\n ...(state.updatedAt ? { updated_at: state.updatedAt } : {}),\n assignees: githubUsers(state.assignees),\n },\n },\n };\n}\n\n/**\n * The label-drift replay: an open issue whose labels changed without a\n * `labeled`/`unlabeled` webhook ever arriving (Factory was down, the delivery\n * was lost, or the label was applied by something other than a delivery the\n * webhook saw). Synthesized as an `opened` delivery so the deployment's\n * `issueOpened` rule decides placement, exactly as it does at arrival — one\n * source of placement policy for both.\n */\nexport function reconciledIssueRelabeledEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n const labels = state.labels ?? [];\n // GitHub updates `updated_at` for a label change. Including it makes retries\n // of one observed issue version idempotent while allowing A → B → A to replay\n // its final A placement as a new version. Synthetic callers without it retain\n // the legacy label-only identity.\n const digest = createHash('sha256')\n .update([...labels].sort().join('\\n'))\n .digest('hex')\n .slice(0, 16);\n const version = state.updatedAt ? `:${createHash('sha256').update(state.updatedAt).digest('hex').slice(0, 16)}` : '';\n return {\n event: 'issues',\n deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:relabeled:${digest}${version}`,\n payload: {\n // `opened` is the event that carries an issue's labels through the rules;\n // an already-filed card is re-placed by the decision, not re-materialized.\n action: 'opened',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? 'github' },\n issue: {\n number: issueNumber,\n title: state.title,\n html_url: state.url,\n state: 'open',\n ...(state.createdAt ? { created_at: state.createdAt } : {}),\n ...(state.updatedAt ? { updated_at: state.updatedAt } : {}),\n assignees: githubUsers(state.assignees),\n labels: githubLabels(labels),\n },\n },\n };\n}\n\n/**\n * The missed-open replay: an open issue with no Work card, because its\n * `opened` delivery never reached the rules ingress. Synthesized as the same\n * `opened` delivery so the deployment's `issueOpened` rule decides whether and\n * where it lands, exactly as it would have at arrival. The delivery id is\n * stable per issue so repeat sweeps dedupe at the ingress.\n */\nexport function reconciledIssueOpenedEvent(\n repository: ReconcileRepository,\n issueNumber: number,\n state: ReconcileIssueState,\n): ParsedGithubWebhook {\n const event = reconciledIssueRelabeledEvent(repository, issueNumber, state);\n return { ...event, deliveryId: `reconcile:${repository.id}:issue:${issueNumber}:opened` };\n}\n\nexport function polledPullRequestEvent(\n repository: ReconcileRepository,\n pullRequestNumber: number,\n state: PolledPullRequestState,\n): ParsedGithubWebhook {\n return {\n event: 'pull_request',\n deliveryId: `poll:${repository.id}:pull-request:${pullRequestNumber}:${state.createdAt}`,\n payload: {\n action: 'opened',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.author ?? '__unknown__' },\n pull_request: pullRequestPayload(pullRequestNumber, state),\n },\n };\n}\n\nexport function reconciledClosedEvent(\n repository: ReconcileRepository,\n pullRequestNumber: number,\n state: ReconcilePullRequestState,\n): ParsedGithubWebhook {\n const outcome = state.merged ? 'merged' : 'closed';\n return {\n event: 'pull_request',\n // Stable per (repository, PR, outcome): the ingress dedupe makes repeat\n // reconcile cycles replay instead of re-committing decisions.\n deliveryId: `reconcile:${repository.id}:pull-request:${pullRequestNumber}:${outcome}`,\n payload: {\n action: 'closed',\n installation: { id: repository.installationId },\n repository: { id: repository.id, full_name: repository.fullName },\n sender: { login: state.mergedBy ?? 'github' },\n pull_request: pullRequestPayload(pullRequestNumber, { ...state, state: 'closed' }),\n },\n };\n}\n\nfunction pullRequestPayload(pullRequestNumber: number, state: ReconcilePullRequestState): Record<string, unknown> {\n const payload: Record<string, unknown> = {\n number: pullRequestNumber,\n title: state.title,\n html_url: state.url,\n state: state.state,\n draft: state.draft,\n merged: state.merged,\n assignees: githubUsers(state.assignees),\n requested_reviewers: githubUsers(state.requestedReviewers),\n labels: githubLabels(state.labels),\n head: { ref: state.headBranch },\n base: { ref: state.baseBranch },\n };\n if (state.createdAt) payload.created_at = state.createdAt;\n if (state.author) payload.user = { login: state.author };\n return payload;\n}\n\nfunction githubUsers(logins: readonly string[] = []): Array<{ login: string }> {\n return logins.map(login => ({ login }));\n}\n\nfunction githubLabels(names: readonly string[] = []): Array<{ name: string }> {\n return names.map(name => ({ name }));\n}\n\nfunction reconciledPullRequestMetadata(\n state: ReconcilePullRequestState,\n reconciliation: 'clear' | 'settled',\n authorTrusted?: boolean,\n): Record<string, unknown> {\n return {\n state: state.state,\n draft: state.draft,\n merged: state.merged,\n ...(state.author ? { author: state.author } : {}),\n ...(state.assignees ? { assignees: state.assignees } : {}),\n ...(state.requestedReviewers ? { requestedReviewers: state.requestedReviewers } : {}),\n ...(state.labels ? { labels: state.labels } : {}),\n ...(authorTrusted === undefined ? {} : { authorTrusted }),\n [FACTORY_PULL_REQUEST_RECONCILIATION_KEY]:\n reconciliation === 'settled' ? (state.merged ? 'merged' : 'closed') : null,\n };\n}\n\nfunction reconciledPullRequestOutcome(metadata: Record<string, unknown>): 'merged' | 'closed' | undefined {\n if (metadata.state !== 'closed' || typeof metadata.merged !== 'boolean') return undefined;\n return metadata.merged ? 'merged' : 'closed';\n}\n\n/**\n * The webhook handler retires subscriptions itself; the sweep replays only the\n * rules ingress, so without this the thread's PR chip and the workspace row\n * stay `open` forever on a deployment GitHub cannot reach.\n */\nasync function retireReconciledSubscriptions(\n storage: IntegrationStorageHandle,\n repository: ReconcileRepository,\n pullRequestNumber: number,\n merged: boolean,\n): Promise<void> {\n const target = changeRequestTargetKey({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n changeRequestId: String(pullRequestNumber),\n });\n const rows = await storage.subscriptions.listByTarget(target);\n await Promise.all(\n rows\n .filter(row => row.status === 'open')\n .map(row => storage.subscriptions.updateStatus(row.id, merged ? 'merged' : 'closed')),\n );\n}\n\n/**\n * State-based safety net for merge signals: webhooks and event-log tailing\n * can miss a merge (cursor gaps, downtime, terminally failed decisions), so\n * this sweep compares still-open PR cards against actual GitHub state and\n * replays the merge through the normal rules ingress when they disagree.\n */\nexport function createGithubPullRequestReconciler(\n options: GithubRulesOptions,\n fetchPullRequest: GithubPullRequestFetcher,\n): GithubPullRequestReconciler {\n const rules = new GithubRules(options);\n return async repositories => {\n const summary: ReconcileSweepSummary = {\n repositories: 0,\n checked: 0,\n merged: 0,\n closed: 0,\n failed: 0,\n errors: [],\n };\n const recordFailure = (repository: ReconcileRepository, error: unknown, pullRequestNumber?: number) => {\n summary.failed += 1;\n if (summary.errors.length < RECONCILE_ERROR_SAMPLE_LIMIT) {\n summary.errors.push({\n repository: repository.fullName,\n ...(pullRequestNumber === undefined ? {} : { pullRequestNumber }),\n error: error instanceof Error ? error.message : String(error),\n });\n }\n };\n // An installation can expose hundreds of repositories; only the ones\n // actually linked to a factory project can have cards to reconcile, so\n // scope the sweep to those up front instead of probing each repository.\n const configured = new Set(\n (await options.sourceControl.projectRepositories.listConfiguredExternalKeys()).map(\n key => `${key.installationExternalId}\\u0000${key.repositoryExternalId}`,\n ),\n );\n const scoped = repositories.filter(repository =>\n configured.has(`${repository.installationId}\\u0000${repository.id}`),\n );\n summary.repositories = scoped.length;\n for (const repository of scoped) {\n // One broken repository (or a failing token exchange for its\n // installation) must not abort the sweep for the others.\n let cardsByNumber: Map<number, WorkItemRow[]>;\n let unanswered: Array<{ item: WorkItemRow; author: string }>;\n try {\n const projects = await options.sourceControl.projectRepositories.listByExternalRepository({\n installationExternalId: String(repository.installationId),\n repositoryExternalId: String(repository.id),\n });\n if (projects.length === 0) continue;\n cardsByNumber = new Map<number, WorkItemRow[]>();\n unanswered = [];\n for (const project of projects) {\n const items = await options.storage.list({\n orgId: project.orgId,\n factoryProjectId: project.factoryProjectId,\n });\n for (const item of items) {\n const unansweredAuthor = authorAwaitingTrust(item, repository);\n if (unansweredAuthor) unanswered.push({ item, author: unansweredAuthor });\n const pullRequestNumber = reconcilablePullRequestNumber(item, repository);\n if (!pullRequestNumber) continue;\n const metadata = item.metadata ?? {};\n const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];\n const reconciledOutcome = reconciledPullRequestOutcome(metadata);\n if (\n workItemPhaseSemantics(options.boards, item)?.kind === 'terminal' &&\n reconciledOutcome !== undefined &&\n reconciliation === reconciledOutcome\n ) {\n continue;\n }\n const cards = cardsByNumber.get(pullRequestNumber) ?? [];\n cards.push(item);\n cardsByNumber.set(pullRequestNumber, cards);\n }\n }\n } catch (error) {\n recordFailure(repository, error);\n continue;\n }\n const authorTrust = sweepTrustLookup(options.github, repository);\n for (const { item, author } of unanswered) {\n try {\n await options.storage.update({\n orgId: item.orgId,\n id: item.id,\n userId: 'factory-rule-dispatcher',\n patch: { metadata: { authorTrusted: await authorTrust(author) } },\n });\n } catch (error) {\n recordFailure(repository, error);\n }\n }\n for (const [pullRequestNumber, cards] of cardsByNumber) {\n try {\n const state = await fetchPullRequest({\n installationId: repository.installationId,\n repository: repository.fullName,\n number: pullRequestNumber,\n });\n summary.checked += 1;\n if (!state) continue;\n // Re-stamped on every sweep so revoked write access reads untrusted\n // within one cycle; a failed lookup keeps the last stamp and retries.\n let authorTrusted: boolean | undefined;\n if (state.author !== undefined) {\n try {\n authorTrusted = await authorTrust(state.author);\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n for (const card of cards) {\n if (state.state === 'closed') continue;\n const metadata = card.metadata ?? {};\n const statusChanged =\n metadata.state !== state.state || metadata.draft !== state.draft || metadata.merged !== state.merged;\n const authorChanged = state.author !== undefined && metadata.author !== state.author;\n const assigneesChanged = !sameStrings(metadata.assignees, state.assignees);\n const reviewersChanged = !sameStrings(metadata.requestedReviewers, state.requestedReviewers);\n const labelsChanged = !sameStrings(metadata.labels, state.labels);\n const trustStale = authorTrusted !== undefined && metadata.authorTrusted !== authorTrusted;\n const metadataChanged =\n statusChanged || authorChanged || assigneesChanged || reviewersChanged || labelsChanged || trustStale;\n const reconciliation = metadata[FACTORY_PULL_REQUEST_RECONCILIATION_KEY];\n if (!metadataChanged && reconciliation !== 'merged' && reconciliation !== 'closed') continue;\n try {\n await options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: {\n metadata: reconciledPullRequestMetadata(state, 'clear', trustStale ? authorTrusted : undefined),\n },\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n if (state.state !== 'closed') continue;\n const cleanupFailures = new Set<string>();\n for (const card of cards) {\n if (workItemPhaseSemantics(options.boards, card)?.kind !== 'terminal') continue;\n try {\n await options.storage.supersedeDecisionsForWorkItem({\n orgId: card.orgId,\n factoryProjectId: card.factoryProjectId,\n workItemId: card.id,\n supersededAt: new Date(),\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n cleanupFailures.add(card.id);\n }\n }\n await rules.ingest(reconciledClosedEvent(repository, pullRequestNumber, state));\n await retireReconciledSubscriptions(options.integrationStorage, repository, pullRequestNumber, state.merged);\n for (const card of cards) {\n if (cleanupFailures.has(card.id)) continue;\n const trustStale = authorTrusted !== undefined && (card.metadata ?? {}).authorTrusted !== authorTrusted;\n try {\n await options.storage.update({\n orgId: card.orgId,\n id: card.id,\n userId: 'factory-rule-dispatcher',\n patch: {\n metadata: reconciledPullRequestMetadata(state, 'settled', trustStale ? authorTrusted : undefined),\n },\n });\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n if (state.merged) summary.merged += 1;\n else summary.closed += 1;\n } catch (error) {\n recordFailure(repository, error, pullRequestNumber);\n }\n }\n }\n return summary;\n };\n}\n\nexport function githubRulesOptions(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n): GithubRulesOptions | undefined {\n if (!context.runtime) return undefined;\n return {\n github,\n sourceControl: context.storage.sourceControl,\n integrationStorage: context.storage.generic,\n projects: context.storage.projects,\n storage: context.runtime.workItems,\n configVersion: context.runtime.configVersion,\n boards: context.runtime.boards,\n intake: context.storage.intake,\n ...(context.hooks?.onRepositoryPush ? { onRepositoryPush: context.hooks.onRepositoryPush } : {}),\n };\n}\n\nexport function attachGithubRules(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n): ((event: ParsedGithubWebhook) => Promise<unknown>) | undefined {\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n const rules = new GithubRules(options);\n return event => rules.ingest(event);\n}\n\nexport function attachGithubReconciler(\n github: GithubRulesIntegration,\n context: IntegrationContext,\n fetchPullRequest: GithubPullRequestFetcher,\n): GithubPullRequestReconciler | undefined {\n const options = githubRulesOptions(github, context);\n if (!options) return undefined;\n return createGithubPullRequestReconciler(options, fetchPullRequest);\n}\n"],"mappings":"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"}