@urateam/core 0.1.16 → 0.1.18

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 (270) hide show
  1. package/dist/__tests__/agentic-deep-review-provider.test.d.ts +2 -0
  2. package/dist/__tests__/agentic-deep-review-provider.test.d.ts.map +1 -0
  3. package/dist/__tests__/agentic-deep-review-provider.test.js +70 -0
  4. package/dist/__tests__/agentic-deep-review-provider.test.js.map +1 -0
  5. package/dist/__tests__/audit-immutability.test.js +16 -1
  6. package/dist/__tests__/audit-immutability.test.js.map +1 -1
  7. package/dist/__tests__/cost/per-run-multi-model.test.d.ts +2 -0
  8. package/dist/__tests__/cost/per-run-multi-model.test.d.ts.map +1 -0
  9. package/dist/__tests__/cost/per-run-multi-model.test.js +102 -0
  10. package/dist/__tests__/cost/per-run-multi-model.test.js.map +1 -0
  11. package/dist/__tests__/db-qa-gap-issues.test.d.ts +2 -0
  12. package/dist/__tests__/db-qa-gap-issues.test.d.ts.map +1 -0
  13. package/dist/__tests__/db-qa-gap-issues.test.js +113 -0
  14. package/dist/__tests__/db-qa-gap-issues.test.js.map +1 -0
  15. package/dist/__tests__/db-release-decisions.test.d.ts +2 -0
  16. package/dist/__tests__/db-release-decisions.test.d.ts.map +1 -0
  17. package/dist/__tests__/db-release-decisions.test.js +98 -0
  18. package/dist/__tests__/db-release-decisions.test.js.map +1 -0
  19. package/dist/__tests__/db-review-model-runs.test.d.ts +2 -0
  20. package/dist/__tests__/db-review-model-runs.test.d.ts.map +1 -0
  21. package/dist/__tests__/db-review-model-runs.test.js +90 -0
  22. package/dist/__tests__/db-review-model-runs.test.js.map +1 -0
  23. package/dist/__tests__/e2e-fanout.test.d.ts +17 -0
  24. package/dist/__tests__/e2e-fanout.test.d.ts.map +1 -0
  25. package/dist/__tests__/e2e-fanout.test.js +184 -0
  26. package/dist/__tests__/e2e-fanout.test.js.map +1 -0
  27. package/dist/__tests__/e2e-pipeline.test.js +1 -0
  28. package/dist/__tests__/e2e-pipeline.test.js.map +1 -1
  29. package/dist/__tests__/notifier-discord.test.js +3 -3
  30. package/dist/__tests__/notifier-discord.test.js.map +1 -1
  31. package/dist/__tests__/notifier-slack.test.js +2 -2
  32. package/dist/__tests__/notifier-slack.test.js.map +1 -1
  33. package/dist/__tests__/notifier.test.js +1 -0
  34. package/dist/__tests__/notifier.test.js.map +1 -1
  35. package/dist/__tests__/openrouter-client.test.d.ts +2 -0
  36. package/dist/__tests__/openrouter-client.test.d.ts.map +1 -0
  37. package/dist/__tests__/openrouter-client.test.js +56 -0
  38. package/dist/__tests__/openrouter-client.test.js.map +1 -0
  39. package/dist/__tests__/openrouter-fanout.test.d.ts +2 -0
  40. package/dist/__tests__/openrouter-fanout.test.d.ts.map +1 -0
  41. package/dist/__tests__/openrouter-fanout.test.js +93 -0
  42. package/dist/__tests__/openrouter-fanout.test.js.map +1 -0
  43. package/dist/__tests__/post-fanout-comments.test.d.ts +2 -0
  44. package/dist/__tests__/post-fanout-comments.test.d.ts.map +1 -0
  45. package/dist/__tests__/post-fanout-comments.test.js +84 -0
  46. package/dist/__tests__/post-fanout-comments.test.js.map +1 -0
  47. package/dist/__tests__/qa-audit-events.test.d.ts +2 -0
  48. package/dist/__tests__/qa-audit-events.test.d.ts.map +1 -0
  49. package/dist/__tests__/qa-audit-events.test.js +57 -0
  50. package/dist/__tests__/qa-audit-events.test.js.map +1 -0
  51. package/dist/__tests__/qa-config.test.d.ts +2 -0
  52. package/dist/__tests__/qa-config.test.d.ts.map +1 -0
  53. package/dist/__tests__/qa-config.test.js +80 -0
  54. package/dist/__tests__/qa-config.test.js.map +1 -0
  55. package/dist/__tests__/qa-eval.test.d.ts +2 -0
  56. package/dist/__tests__/qa-eval.test.d.ts.map +1 -0
  57. package/dist/__tests__/qa-eval.test.js +146 -0
  58. package/dist/__tests__/qa-eval.test.js.map +1 -0
  59. package/dist/__tests__/qa-gap.test.d.ts +2 -0
  60. package/dist/__tests__/qa-gap.test.d.ts.map +1 -0
  61. package/dist/__tests__/qa-gap.test.js +100 -0
  62. package/dist/__tests__/qa-gap.test.js.map +1 -0
  63. package/dist/__tests__/qa-github.test.d.ts +2 -0
  64. package/dist/__tests__/qa-github.test.d.ts.map +1 -0
  65. package/dist/__tests__/qa-github.test.js +162 -0
  66. package/dist/__tests__/qa-github.test.js.map +1 -0
  67. package/dist/__tests__/ralph-review-fix-regression.test.js +1 -0
  68. package/dist/__tests__/ralph-review-fix-regression.test.js.map +1 -1
  69. package/dist/__tests__/release-manager-audit-events.test.d.ts +2 -0
  70. package/dist/__tests__/release-manager-audit-events.test.d.ts.map +1 -0
  71. package/dist/__tests__/release-manager-audit-events.test.js +64 -0
  72. package/dist/__tests__/release-manager-audit-events.test.js.map +1 -0
  73. package/dist/__tests__/release-manager-config.test.d.ts +2 -0
  74. package/dist/__tests__/release-manager-config.test.d.ts.map +1 -0
  75. package/dist/__tests__/release-manager-config.test.js +56 -0
  76. package/dist/__tests__/release-manager-config.test.js.map +1 -0
  77. package/dist/__tests__/release-manager-decide.test.d.ts +2 -0
  78. package/dist/__tests__/release-manager-decide.test.d.ts.map +1 -0
  79. package/dist/__tests__/release-manager-decide.test.js +102 -0
  80. package/dist/__tests__/release-manager-decide.test.js.map +1 -0
  81. package/dist/__tests__/release-manager-github.test.d.ts +2 -0
  82. package/dist/__tests__/release-manager-github.test.d.ts.map +1 -0
  83. package/dist/__tests__/release-manager-github.test.js +83 -0
  84. package/dist/__tests__/release-manager-github.test.js.map +1 -0
  85. package/dist/__tests__/release-manager-license-gate.test.d.ts +2 -0
  86. package/dist/__tests__/release-manager-license-gate.test.d.ts.map +1 -0
  87. package/dist/__tests__/release-manager-license-gate.test.js +25 -0
  88. package/dist/__tests__/release-manager-license-gate.test.js.map +1 -0
  89. package/dist/__tests__/release-manager-scheduler.test.d.ts +2 -0
  90. package/dist/__tests__/release-manager-scheduler.test.d.ts.map +1 -0
  91. package/dist/__tests__/release-manager-scheduler.test.js +395 -0
  92. package/dist/__tests__/release-manager-scheduler.test.js.map +1 -0
  93. package/dist/__tests__/release-manager-slack-handler.test.d.ts +2 -0
  94. package/dist/__tests__/release-manager-slack-handler.test.d.ts.map +1 -0
  95. package/dist/__tests__/release-manager-slack-handler.test.js +175 -0
  96. package/dist/__tests__/release-manager-slack-handler.test.js.map +1 -0
  97. package/dist/__tests__/release-manager-triggers.test.d.ts +2 -0
  98. package/dist/__tests__/release-manager-triggers.test.d.ts.map +1 -0
  99. package/dist/__tests__/release-manager-triggers.test.js +67 -0
  100. package/dist/__tests__/release-manager-triggers.test.js.map +1 -0
  101. package/dist/__tests__/release-manager-versioning.test.d.ts +2 -0
  102. package/dist/__tests__/release-manager-versioning.test.d.ts.map +1 -0
  103. package/dist/__tests__/release-manager-versioning.test.js +51 -0
  104. package/dist/__tests__/release-manager-versioning.test.js.map +1 -0
  105. package/dist/__tests__/review-prompt.test.d.ts +2 -0
  106. package/dist/__tests__/review-prompt.test.d.ts.map +1 -0
  107. package/dist/__tests__/review-prompt.test.js +88 -0
  108. package/dist/__tests__/review-prompt.test.js.map +1 -0
  109. package/dist/__tests__/review-provider-registry.test.d.ts +2 -0
  110. package/dist/__tests__/review-provider-registry.test.d.ts.map +1 -0
  111. package/dist/__tests__/review-provider-registry.test.js +61 -0
  112. package/dist/__tests__/review-provider-registry.test.js.map +1 -0
  113. package/dist/__tests__/runner-fanout-integration.test.d.ts +2 -0
  114. package/dist/__tests__/runner-fanout-integration.test.d.ts.map +1 -0
  115. package/dist/__tests__/runner-fanout-integration.test.js +107 -0
  116. package/dist/__tests__/runner-fanout-integration.test.js.map +1 -0
  117. package/dist/audit/events.d.ts +54 -0
  118. package/dist/audit/events.d.ts.map +1 -1
  119. package/dist/audit/events.js +100 -0
  120. package/dist/audit/events.js.map +1 -1
  121. package/dist/audit/writer.d.ts +22 -8
  122. package/dist/audit/writer.d.ts.map +1 -1
  123. package/dist/audit/writer.js +22 -8
  124. package/dist/audit/writer.js.map +1 -1
  125. package/dist/cost/aggregate.d.ts.map +1 -1
  126. package/dist/cost/aggregate.js +14 -2
  127. package/dist/cost/aggregate.js.map +1 -1
  128. package/dist/cost/csv.d.ts.map +1 -1
  129. package/dist/cost/csv.js +14 -2
  130. package/dist/cost/csv.js.map +1 -1
  131. package/dist/cost/per-run.d.ts +11 -0
  132. package/dist/cost/per-run.d.ts.map +1 -1
  133. package/dist/cost/per-run.js +21 -8
  134. package/dist/cost/per-run.js.map +1 -1
  135. package/dist/cost/rollup.d.ts.map +1 -1
  136. package/dist/cost/rollup.js +14 -2
  137. package/dist/cost/rollup.js.map +1 -1
  138. package/dist/db/client.d.ts.map +1 -1
  139. package/dist/db/client.js +20 -1
  140. package/dist/db/client.js.map +1 -1
  141. package/dist/db/migrations/postgres/009_review_model_runs.sql +18 -0
  142. package/dist/db/migrations/postgres/010_release_manager.sql +38 -0
  143. package/dist/db/migrations/postgres/011_qa_run_columns.sql +8 -0
  144. package/dist/db/migrations/postgres/012_qa_gap_issues.sql +18 -0
  145. package/dist/db/migrations/sqlite/008_review_model_runs.sql +18 -0
  146. package/dist/db/migrations/sqlite/009_release_manager.sql +43 -0
  147. package/dist/db/migrations/sqlite/010_qa_run_columns.sql +9 -0
  148. package/dist/db/migrations/sqlite/011_qa_gap_issues.sql +22 -0
  149. package/dist/db/review-model-runs.d.ts +4 -0
  150. package/dist/db/review-model-runs.d.ts.map +1 -0
  151. package/dist/db/review-model-runs.js +25 -0
  152. package/dist/db/review-model-runs.js.map +1 -0
  153. package/dist/db/schema.d.ts +761 -0
  154. package/dist/db/schema.d.ts.map +1 -1
  155. package/dist/db/schema.js +67 -0
  156. package/dist/db/schema.js.map +1 -1
  157. package/dist/executor/executor.d.ts.map +1 -1
  158. package/dist/executor/executor.js +2 -0
  159. package/dist/executor/executor.js.map +1 -1
  160. package/dist/executor/review/agentic-deep-review.d.ts +6 -0
  161. package/dist/executor/review/agentic-deep-review.d.ts.map +1 -0
  162. package/dist/executor/review/agentic-deep-review.js +37 -0
  163. package/dist/executor/review/agentic-deep-review.js.map +1 -0
  164. package/dist/executor/review/openrouter-client.d.ts +23 -0
  165. package/dist/executor/review/openrouter-client.d.ts.map +1 -0
  166. package/dist/executor/review/openrouter-client.js +34 -0
  167. package/dist/executor/review/openrouter-client.js.map +1 -0
  168. package/dist/executor/review/openrouter-fanout.d.ts +17 -0
  169. package/dist/executor/review/openrouter-fanout.d.ts.map +1 -0
  170. package/dist/executor/review/openrouter-fanout.js +84 -0
  171. package/dist/executor/review/openrouter-fanout.js.map +1 -0
  172. package/dist/executor/review/post-fanout-comments.d.ts +4 -0
  173. package/dist/executor/review/post-fanout-comments.d.ts.map +1 -0
  174. package/dist/executor/review/post-fanout-comments.js +45 -0
  175. package/dist/executor/review/post-fanout-comments.js.map +1 -0
  176. package/dist/executor/review/review-prompt.d.ts +21 -0
  177. package/dist/executor/review/review-prompt.d.ts.map +1 -0
  178. package/dist/executor/review/review-prompt.js +130 -0
  179. package/dist/executor/review/review-prompt.js.map +1 -0
  180. package/dist/executor/review/review-provider.d.ts +27 -0
  181. package/dist/executor/review/review-provider.d.ts.map +1 -0
  182. package/dist/executor/review/review-provider.js +36 -0
  183. package/dist/executor/review/review-provider.js.map +1 -0
  184. package/dist/executor/review/workdir-snapshot.d.ts +13 -0
  185. package/dist/executor/review/workdir-snapshot.d.ts.map +1 -0
  186. package/dist/executor/review/workdir-snapshot.js +24 -0
  187. package/dist/executor/review/workdir-snapshot.js.map +1 -0
  188. package/dist/index.d.ts +4 -0
  189. package/dist/index.d.ts.map +1 -1
  190. package/dist/index.js +4 -0
  191. package/dist/index.js.map +1 -1
  192. package/dist/license.d.ts.map +1 -1
  193. package/dist/license.js +1 -0
  194. package/dist/license.js.map +1 -1
  195. package/dist/pipeline/review-providers-runner.d.ts +31 -0
  196. package/dist/pipeline/review-providers-runner.d.ts.map +1 -0
  197. package/dist/pipeline/review-providers-runner.js +64 -0
  198. package/dist/pipeline/review-providers-runner.js.map +1 -0
  199. package/dist/pipeline/runner.d.ts.map +1 -1
  200. package/dist/pipeline/runner.js +99 -7
  201. package/dist/pipeline/runner.js.map +1 -1
  202. package/dist/pm/actions/promote.js +2 -2
  203. package/dist/pm/actions/promote.js.map +1 -1
  204. package/dist/pm/actions/resolve-approvals.js +3 -3
  205. package/dist/pm/actions/resolve-approvals.js.map +1 -1
  206. package/dist/pm/actions/triage.js +2 -2
  207. package/dist/pm/actions/triage.js.map +1 -1
  208. package/dist/pm/scheduler.js +3 -3
  209. package/dist/pm/scheduler.js.map +1 -1
  210. package/dist/pm/slack-interface.d.ts +8 -0
  211. package/dist/pm/slack-interface.d.ts.map +1 -1
  212. package/dist/pm/slack-interface.js +20 -3
  213. package/dist/pm/slack-interface.js.map +1 -1
  214. package/dist/qa/gap.d.ts +29 -0
  215. package/dist/qa/gap.d.ts.map +1 -0
  216. package/dist/qa/gap.js +91 -0
  217. package/dist/qa/gap.js.map +1 -0
  218. package/dist/qa/github.d.ts +77 -0
  219. package/dist/qa/github.d.ts.map +1 -0
  220. package/dist/qa/github.js +106 -0
  221. package/dist/qa/github.js.map +1 -0
  222. package/dist/qa/index.d.ts +4 -0
  223. package/dist/qa/index.d.ts.map +1 -0
  224. package/dist/qa/index.js +4 -0
  225. package/dist/qa/index.js.map +1 -0
  226. package/dist/qa/types.d.ts +44 -0
  227. package/dist/qa/types.d.ts.map +1 -0
  228. package/dist/qa/types.js +12 -0
  229. package/dist/qa/types.js.map +1 -0
  230. package/dist/release-manager/decide.d.ts +26 -0
  231. package/dist/release-manager/decide.d.ts.map +1 -0
  232. package/dist/release-manager/decide.js +58 -0
  233. package/dist/release-manager/decide.js.map +1 -0
  234. package/dist/release-manager/github.d.ts +47 -0
  235. package/dist/release-manager/github.d.ts.map +1 -0
  236. package/dist/release-manager/github.js +66 -0
  237. package/dist/release-manager/github.js.map +1 -0
  238. package/dist/release-manager/index.d.ts +9 -0
  239. package/dist/release-manager/index.d.ts.map +1 -0
  240. package/dist/release-manager/index.js +9 -0
  241. package/dist/release-manager/index.js.map +1 -0
  242. package/dist/release-manager/scheduler.d.ts +30 -0
  243. package/dist/release-manager/scheduler.d.ts.map +1 -0
  244. package/dist/release-manager/scheduler.js +427 -0
  245. package/dist/release-manager/scheduler.js.map +1 -0
  246. package/dist/release-manager/slack-handler.d.ts +39 -0
  247. package/dist/release-manager/slack-handler.d.ts.map +1 -0
  248. package/dist/release-manager/slack-handler.js +124 -0
  249. package/dist/release-manager/slack-handler.js.map +1 -0
  250. package/dist/release-manager/state.d.ts +18 -0
  251. package/dist/release-manager/state.d.ts.map +1 -0
  252. package/dist/release-manager/state.js +154 -0
  253. package/dist/release-manager/state.js.map +1 -0
  254. package/dist/release-manager/triggers.d.ts +32 -0
  255. package/dist/release-manager/triggers.d.ts.map +1 -0
  256. package/dist/release-manager/triggers.js +82 -0
  257. package/dist/release-manager/triggers.js.map +1 -0
  258. package/dist/release-manager/types.d.ts +79 -0
  259. package/dist/release-manager/types.d.ts.map +1 -0
  260. package/dist/release-manager/types.js +48 -0
  261. package/dist/release-manager/types.js.map +1 -0
  262. package/dist/release-manager/versioning.d.ts +20 -0
  263. package/dist/release-manager/versioning.d.ts.map +1 -0
  264. package/dist/release-manager/versioning.js +60 -0
  265. package/dist/release-manager/versioning.js.map +1 -0
  266. package/dist/types.d.ts +48 -0
  267. package/dist/types.d.ts.map +1 -1
  268. package/dist/types.js +8 -0
  269. package/dist/types.js.map +1 -1
  270. package/package.json +3 -1
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=agentic-deep-review-provider.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentic-deep-review-provider.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/agentic-deep-review-provider.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect, vi, beforeEach } from "vitest";
2
+ const runDeepReviewMock = vi.fn();
3
+ vi.mock("../executor/deep-review.js", () => ({
4
+ runDeepReview: (...args) => runDeepReviewMock(...args),
5
+ deepFindingsToReviewFindings: (findings) => findings,
6
+ }));
7
+ const makeHandoff = () => ({
8
+ runId: "r1",
9
+ issueId: "i1",
10
+ stage: "review",
11
+ timestamp: new Date().toISOString(),
12
+ summary: "",
13
+ filesChanged: [],
14
+ approach: "",
15
+ context: { issueIntent: "do x", constraints: [], assumptions: [] },
16
+ tokenBudget: { contextTokensUsed: 0, recommendedMaxTurns: 0 },
17
+ });
18
+ describe("AgenticDeepReviewProvider", () => {
19
+ beforeEach(() => { runDeepReviewMock.mockReset(); });
20
+ it("returns a single ReviewModelRun with completed status on success", async () => {
21
+ runDeepReviewMock.mockResolvedValue({
22
+ findings: [
23
+ { severity: "warning", file: "a.ts", line: 1, category: "x", description: "d", fix: "f" },
24
+ ],
25
+ inputTokens: 100,
26
+ outputTokens: 50,
27
+ });
28
+ const { AgenticDeepReviewProvider } = await import("../executor/review/agentic-deep-review.js");
29
+ const provider = new AgenticDeepReviewProvider();
30
+ const handoff = makeHandoff();
31
+ const runs = await provider.runReview({
32
+ runId: "r1",
33
+ stageRunId: "s1",
34
+ workdir: "/tmp/x",
35
+ handoff,
36
+ baseRef: "main",
37
+ prNumber: null,
38
+ });
39
+ expect(runs).toHaveLength(1);
40
+ expect(runs[0].providerId).toBe("agentic");
41
+ expect(runs[0].status).toBe("completed");
42
+ expect(runs[0].modelId).toBe("claude-haiku-4-5-20251001");
43
+ expect(runs[0].findings).toHaveLength(1);
44
+ expect(runs[0].inputTokens).toBe(100);
45
+ expect(runs[0].outputTokens).toBe(50);
46
+ expect(runs[0].durationMs).toBeGreaterThanOrEqual(0);
47
+ expect(runDeepReviewMock).toHaveBeenCalledOnce();
48
+ expect(runDeepReviewMock).toHaveBeenCalledWith(handoff, "/tmp/x");
49
+ });
50
+ it("returns failed run with errorMessage when runDeepReview throws", async () => {
51
+ runDeepReviewMock.mockRejectedValue(new Error("agent sdk down"));
52
+ const { AgenticDeepReviewProvider } = await import("../executor/review/agentic-deep-review.js");
53
+ const provider = new AgenticDeepReviewProvider();
54
+ const handoff = makeHandoff();
55
+ const runs = await provider.runReview({
56
+ runId: "r1",
57
+ stageRunId: "s1",
58
+ workdir: "/tmp/x",
59
+ handoff,
60
+ baseRef: "main",
61
+ prNumber: null,
62
+ });
63
+ expect(runs).toHaveLength(1);
64
+ expect(runs[0].status).toBe("failed");
65
+ expect(runs[0].errorMessage).toContain("agent sdk down");
66
+ expect(runs[0].findings).toHaveLength(0);
67
+ expect(runs[0].durationMs).toBeGreaterThanOrEqual(0);
68
+ });
69
+ });
70
+ //# sourceMappingURL=agentic-deep-review-provider.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agentic-deep-review-provider.test.js","sourceRoot":"","sources":["../../src/__tests__/agentic-deep-review-provider.test.ts"],"names":[],"mappings":"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"}
@@ -37,11 +37,26 @@ describe("audit_events immutability", () => {
37
37
  .filter((file) => !allowed.some((a) => file.endsWith(a) || file === a));
38
38
  expect(offenders, `Unauthorized audit_events mutation in:\n${offenders.join("\n")}`).toEqual([]);
39
39
  });
40
- it("logAuditEventUnchecked is only called from license.ts", () => {
40
+ it("logAuditEventUnchecked is only called from license.ts or Pro-tier feature modules", () => {
41
41
  const repoRoot = path.resolve(__dirname, "../../../..");
42
+ // logAuditEventUnchecked is allowed in:
43
+ // 1. The writer itself (definition)
44
+ // 2. license.ts (license-validation failure path)
45
+ // 3. Pro-tier feature modules (PM agent, Release Manager) — their audit events
46
+ // must appear in the audit table whenever the Pro feature is licensed,
47
+ // independent of the Enterprise audit-log dashboard being unlocked.
48
+ // 4. This test file
42
49
  const allowed = [
43
50
  "packages/core/src/audit/writer.ts",
44
51
  "packages/core/src/license.ts",
52
+ "packages/core/src/pm/scheduler.ts",
53
+ "packages/core/src/pm/actions/triage.ts",
54
+ "packages/core/src/pm/actions/promote.ts",
55
+ "packages/core/src/pm/actions/resolve-approvals.ts",
56
+ "packages/core/src/release-manager/scheduler.ts",
57
+ "packages/core/src/release-manager/slack-handler.ts",
58
+ "packages/core/src/qa/github.ts",
59
+ "packages/core/src/qa/gap.ts",
45
60
  "packages/core/src/__tests__/audit-immutability.test.ts",
46
61
  ];
47
62
  let matches = [];
@@ -1 +1 @@
1
- {"version":3,"file":"audit-immutability.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-immutability.test.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"audit-immutability.test.js","sourceRoot":"","sources":["../../src/__tests__/audit-immutability.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=per-run-multi-model.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-run-multi-model.test.d.ts","sourceRoot":"","sources":["../../../src/__tests__/cost/per-run-multi-model.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,102 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from "vitest";
2
+ import { computeRunCost } from "../../cost/per-run.js";
3
+ import { installTestProLicense, restoreLicense } from "../helpers/license.js";
4
+ // computeRunCost short-circuits to zero without an enterprise license.
5
+ beforeEach(async () => {
6
+ await installTestProLicense("enterprise");
7
+ });
8
+ afterEach(async () => {
9
+ await restoreLicense();
10
+ });
11
+ const config = {
12
+ costs: {
13
+ modelPricing: {
14
+ "claude-haiku-4-5-20251001": { inputPerMillion: 1, outputPerMillion: 5 },
15
+ "anthropic/claude-3.5-sonnet": { inputPerMillion: 3, outputPerMillion: 15 },
16
+ "claude-sonnet-4-6": { inputPerMillion: 3, outputPerMillion: 15 },
17
+ },
18
+ hourlyEngRate: 50,
19
+ timeSavedPerPrDefault: 4,
20
+ },
21
+ pipelineConfigs: {
22
+ "auto-implement": {
23
+ stageModels: { implement: "claude-sonnet-4-6" },
24
+ profile: { model: "claude-sonnet-4-6" },
25
+ timeSavedPerPr: 6,
26
+ },
27
+ },
28
+ };
29
+ describe("computeRunCost — multi-model rollup (BEC-134)", () => {
30
+ it("uses modelRuns per-model pricing when present", () => {
31
+ const run = { pipelineKey: "auto-implement", status: "completed" };
32
+ const stages = [
33
+ {
34
+ stage: "review",
35
+ inputTokens: 1000, // stage-level totals (ignored when modelRuns present)
36
+ outputTokens: 500,
37
+ modelRuns: [
38
+ // 600/1_000_000 * 1 + 300/1_000_000 * 5 = 0.0006 + 0.0015 = 0.0021
39
+ { modelId: "claude-haiku-4-5-20251001", inputTokens: 600, outputTokens: 300 },
40
+ // 400/1_000_000 * 3 + 200/1_000_000 * 15 = 0.0012 + 0.003 = 0.0042
41
+ { modelId: "anthropic/claude-3.5-sonnet", inputTokens: 400, outputTokens: 200 },
42
+ ],
43
+ },
44
+ ];
45
+ const cost = computeRunCost(run, stages, config);
46
+ // total: 0.0021 + 0.0042 = 0.0063
47
+ expect(cost.dollars).toBeCloseTo(0.0063, 5);
48
+ // token totals come from model rows, not stage-level
49
+ expect(cost.inputTokens).toBe(1000); // 600 + 400
50
+ expect(cost.outputTokens).toBe(500); // 300 + 200
51
+ });
52
+ it("falls back to stage-level rollup when modelRuns is empty", () => {
53
+ const run = { pipelineKey: "auto-implement", status: "completed" };
54
+ const stages = [
55
+ {
56
+ stage: "review",
57
+ inputTokens: 1_000_000,
58
+ outputTokens: 500_000,
59
+ modelRuns: [], // empty → use stage-level fallback
60
+ },
61
+ ];
62
+ const cost = computeRunCost(run, stages, config);
63
+ // review stage uses pipeline profile model: claude-sonnet-4-6 ($3/$15 per M)
64
+ // 1M * $3 + 0.5M * $15 = $3 + $7.5 = $10.5
65
+ expect(cost.dollars).toBeCloseTo(10.5, 2);
66
+ expect(cost.inputTokens).toBe(1_000_000);
67
+ expect(cost.outputTokens).toBe(500_000);
68
+ });
69
+ it("falls back to stage-level rollup when modelRuns is absent", () => {
70
+ const run = { pipelineKey: "auto-implement", status: "completed" };
71
+ const stages = [
72
+ // no modelRuns field at all — backward-compat for pre-BEC-134 rows
73
+ { stage: "implement", inputTokens: 1_000_000, outputTokens: 1_000_000 },
74
+ ];
75
+ const cost = computeRunCost(run, stages, config);
76
+ // implement stage model: claude-sonnet-4-6 ($3/$15 per M)
77
+ // 1M * $3 + 1M * $15 = $18
78
+ expect(cost.dollars).toBeCloseTo(18, 2);
79
+ });
80
+ it("mixes model-run and stage-level stages correctly", () => {
81
+ const run = { pipelineKey: "auto-implement", status: "completed" };
82
+ const stages = [
83
+ // implement: no modelRuns → stage-level fallback (claude-sonnet-4-6)
84
+ { stage: "implement", inputTokens: 1_000_000, outputTokens: 0, modelRuns: [] },
85
+ // review: per-model pricing
86
+ {
87
+ stage: "review",
88
+ inputTokens: 0,
89
+ outputTokens: 0,
90
+ modelRuns: [
91
+ { modelId: "claude-haiku-4-5-20251001", inputTokens: 1_000_000, outputTokens: 0 },
92
+ ],
93
+ },
94
+ ];
95
+ const cost = computeRunCost(run, stages, config);
96
+ // implement: 1M * $3 = $3
97
+ // review haiku: 1M * $1 = $1
98
+ // total: $4
99
+ expect(cost.dollars).toBeCloseTo(4, 5);
100
+ });
101
+ });
102
+ //# sourceMappingURL=per-run-multi-model.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"per-run-multi-model.test.js","sourceRoot":"","sources":["../../../src/__tests__/cost/per-run-multi-model.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db-qa-gap-issues.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-qa-gap-issues.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/db-qa-gap-issues.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,113 @@
1
+ import { describe, it, expect, afterEach } from "vitest";
2
+ import { randomBytes, randomUUID } from "node:crypto";
3
+ import { unlinkSync } from "node:fs";
4
+ import { eq, and } from "drizzle-orm";
5
+ import { createDb } from "../db/index.js";
6
+ import { qaGapIssues, releaseDecisions } from "../db/schema.js";
7
+ function tmpDbPath() {
8
+ const id = randomBytes(8).toString("hex");
9
+ return `/tmp/laf-qa-gap-${id}.sqlite`;
10
+ }
11
+ describe("qa_gap_issues table", () => {
12
+ const paths = [];
13
+ async function makeDb() {
14
+ const path = tmpDbPath();
15
+ paths.push(path);
16
+ const db = await createDb({ driver: "sqlite", connectionString: path });
17
+ return { db: db };
18
+ }
19
+ afterEach(() => {
20
+ for (const p of paths) {
21
+ try {
22
+ unlinkSync(p);
23
+ }
24
+ catch { }
25
+ try {
26
+ unlinkSync(p + "-wal");
27
+ }
28
+ catch { }
29
+ try {
30
+ unlinkSync(p + "-shm");
31
+ }
32
+ catch { }
33
+ }
34
+ paths.length = 0;
35
+ });
36
+ it("inserts and reads a qa_gap_issues row", async () => {
37
+ const { db } = await makeDb();
38
+ const id = `qg_${randomUUID()}`;
39
+ await db.insert(qaGapIssues).values({
40
+ id,
41
+ repoUrl: "https://github.com/org/repo",
42
+ branch: "main",
43
+ workflowPath: ".github/workflows/smoke.yml",
44
+ linearIssueId: "BEC-150",
45
+ });
46
+ const rows = await db.select().from(qaGapIssues).where(eq(qaGapIssues.id, id));
47
+ expect(rows).toHaveLength(1);
48
+ expect(rows[0].linearIssueId).toBe("BEC-150");
49
+ expect(rows[0].resolvedAt).toBeNull();
50
+ });
51
+ it("partial UNIQUE prevents re-filing while resolved_at is null", async () => {
52
+ const { db } = await makeDb();
53
+ await db.insert(qaGapIssues).values({
54
+ id: `qg_${randomUUID()}`,
55
+ repoUrl: "https://github.com/org/repo",
56
+ branch: "main",
57
+ workflowPath: ".github/workflows/smoke.yml",
58
+ linearIssueId: "BEC-150",
59
+ });
60
+ await expect(db.insert(qaGapIssues).values({
61
+ id: `qg_${randomUUID()}`,
62
+ repoUrl: "https://github.com/org/repo",
63
+ branch: "main",
64
+ workflowPath: ".github/workflows/smoke.yml",
65
+ linearIssueId: "BEC-151",
66
+ })).rejects.toThrow();
67
+ });
68
+ it("allows re-filing after the previous issue is resolved", async () => {
69
+ const { db } = await makeDb();
70
+ const firstId = `qg_${randomUUID()}`;
71
+ await db.insert(qaGapIssues).values({
72
+ id: firstId,
73
+ repoUrl: "https://github.com/org/repo",
74
+ branch: "main",
75
+ workflowPath: ".github/workflows/smoke.yml",
76
+ linearIssueId: "BEC-150",
77
+ });
78
+ await db.update(qaGapIssues)
79
+ .set({ resolvedAt: new Date() })
80
+ .where(eq(qaGapIssues.id, firstId));
81
+ // Second filing now succeeds
82
+ await db.insert(qaGapIssues).values({
83
+ id: `qg_${randomUUID()}`,
84
+ repoUrl: "https://github.com/org/repo",
85
+ branch: "main",
86
+ workflowPath: ".github/workflows/smoke.yml",
87
+ linearIssueId: "BEC-160",
88
+ });
89
+ const rows = await db.select().from(qaGapIssues).where(and(eq(qaGapIssues.repoUrl, "https://github.com/org/repo"), eq(qaGapIssues.workflowPath, ".github/workflows/smoke.yml")));
90
+ expect(rows).toHaveLength(2);
91
+ });
92
+ it("releaseDecisions has qaRunId and qaRunSha columns", async () => {
93
+ const { db } = await makeDb();
94
+ const id = `rd_${randomUUID()}`;
95
+ await db.insert(releaseDecisions).values({
96
+ id,
97
+ repoUrl: "https://github.com/org/repo",
98
+ branch: "main",
99
+ decidedAt: new Date(),
100
+ decision: "skip",
101
+ reason: "qa_running",
102
+ triggerStateJson: "{}",
103
+ attemptCount: 0,
104
+ qaRunId: 12345,
105
+ qaRunSha: "abcdef0",
106
+ });
107
+ const rows = await db.select().from(releaseDecisions).where(eq(releaseDecisions.id, id));
108
+ expect(rows).toHaveLength(1);
109
+ expect(rows[0].qaRunId).toBe(12345);
110
+ expect(rows[0].qaRunSha).toBe("abcdef0");
111
+ });
112
+ });
113
+ //# sourceMappingURL=db-qa-gap-issues.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-qa-gap-issues.test.js","sourceRoot":"","sources":["../../src/__tests__/db-qa-gap-issues.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db-release-decisions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-release-decisions.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/db-release-decisions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect, afterEach } from "vitest";
2
+ import { randomBytes, randomUUID } from "node:crypto";
3
+ import { unlinkSync } from "node:fs";
4
+ import { eq, and } from "drizzle-orm";
5
+ import { createDb } from "../db/index.js";
6
+ import { releaseDecisions, releaseApprovals } from "../db/schema.js";
7
+ function tmpDbPath() {
8
+ const id = randomBytes(8).toString("hex");
9
+ return `/tmp/laf-rm-test-${id}.sqlite`;
10
+ }
11
+ describe("release-manager DB tables", () => {
12
+ const paths = [];
13
+ async function makeDb() {
14
+ const path = tmpDbPath();
15
+ paths.push(path);
16
+ const db = await createDb({ driver: "sqlite", connectionString: path });
17
+ return { db: db };
18
+ }
19
+ afterEach(() => {
20
+ for (const p of paths) {
21
+ try {
22
+ unlinkSync(p);
23
+ }
24
+ catch { /* ignore */ }
25
+ try {
26
+ unlinkSync(p + "-wal");
27
+ }
28
+ catch { /* ignore */ }
29
+ try {
30
+ unlinkSync(p + "-shm");
31
+ }
32
+ catch { /* ignore */ }
33
+ }
34
+ });
35
+ it("inserts and reads a release_decisions row", async () => {
36
+ const { db } = await makeDb();
37
+ const id = `rd_${randomUUID()}`;
38
+ await db.insert(releaseDecisions).values({
39
+ id,
40
+ repoUrl: "https://github.com/org/repo",
41
+ branch: "main",
42
+ decidedAt: new Date(),
43
+ decision: "skip",
44
+ reason: "timeSinceLastHours not met",
45
+ triggerStateJson: JSON.stringify({ mergedPRs: 3 }),
46
+ attemptCount: 0,
47
+ });
48
+ const rows = await db.select().from(releaseDecisions).where(eq(releaseDecisions.id, id));
49
+ expect(rows).toHaveLength(1);
50
+ expect(rows[0].decision).toBe("skip");
51
+ expect(rows[0].reason).toBe("timeSinceLastHours not met");
52
+ });
53
+ it("enforces UNIQUE(repo_url, branch, approved_by) WHERE consumed_at IS NULL — second pending approve from same user fails", async () => {
54
+ const { db } = await makeDb();
55
+ await db.insert(releaseApprovals).values({
56
+ id: `ra_${randomUUID()}`,
57
+ repoUrl: "https://github.com/org/repo",
58
+ branch: "main",
59
+ approvedAt: new Date(),
60
+ approvedBy: "U123",
61
+ });
62
+ await expect(db.insert(releaseApprovals).values({
63
+ id: `ra_${randomUUID()}`,
64
+ repoUrl: "https://github.com/org/repo",
65
+ branch: "main",
66
+ approvedAt: new Date(),
67
+ approvedBy: "U123",
68
+ })).rejects.toThrow();
69
+ });
70
+ it("allows a second approve from the same user once the first is consumed", async () => {
71
+ const { db } = await makeDb();
72
+ const firstId = `ra_${randomUUID()}`;
73
+ await db.insert(releaseApprovals).values({
74
+ id: firstId,
75
+ repoUrl: "https://github.com/org/repo",
76
+ branch: "main",
77
+ approvedAt: new Date(),
78
+ approvedBy: "U123",
79
+ });
80
+ await db.update(releaseApprovals)
81
+ .set({ consumedAt: new Date(), consumedByDecisionId: "rd_consumed" })
82
+ .where(eq(releaseApprovals.id, firstId));
83
+ // Second approve should now succeed
84
+ await db.insert(releaseApprovals).values({
85
+ id: `ra_${randomUUID()}`,
86
+ repoUrl: "https://github.com/org/repo",
87
+ branch: "main",
88
+ approvedAt: new Date(),
89
+ approvedBy: "U123",
90
+ });
91
+ const rows = await db
92
+ .select()
93
+ .from(releaseApprovals)
94
+ .where(and(eq(releaseApprovals.repoUrl, "https://github.com/org/repo"), eq(releaseApprovals.approvedBy, "U123")));
95
+ expect(rows).toHaveLength(2);
96
+ });
97
+ });
98
+ //# sourceMappingURL=db-release-decisions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-release-decisions.test.js","sourceRoot":"","sources":["../../src/__tests__/db-release-decisions.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=db-review-model-runs.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-review-model-runs.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/db-review-model-runs.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,90 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import Database from "better-sqlite3";
3
+ import { runMigrationsSqlite } from "../db/migrator.js";
4
+ import { insertReviewModelRuns } from "../db/review-model-runs.js";
5
+ import { drizzle as drizzleSqlite } from "drizzle-orm/better-sqlite3";
6
+ describe("review_model_runs migration (sqlite)", () => {
7
+ it("creates the table with expected columns", () => {
8
+ const db = new Database(":memory:");
9
+ runMigrationsSqlite(db);
10
+ const cols = db
11
+ .prepare("PRAGMA table_info(review_model_runs)")
12
+ .all();
13
+ const names = cols.map((c) => c.name).sort();
14
+ expect(names).toEqual([
15
+ "completed_at",
16
+ "duration_ms",
17
+ "error_message",
18
+ "id",
19
+ "input_tokens",
20
+ "model_id",
21
+ "output_tokens",
22
+ "provider_id",
23
+ "stage_run_id",
24
+ "started_at",
25
+ "status",
26
+ "truncated_files",
27
+ ].sort());
28
+ });
29
+ it("creates an index on stage_run_id", () => {
30
+ const db = new Database(":memory:");
31
+ runMigrationsSqlite(db);
32
+ const indexes = db
33
+ .prepare("PRAGMA index_list(review_model_runs)")
34
+ .all();
35
+ expect(indexes.some((i) => i.name.includes("stage_run_id"))).toBe(true);
36
+ });
37
+ it("inserts and reads rows", () => {
38
+ const db = new Database(":memory:");
39
+ runMigrationsSqlite(db);
40
+ // Need a stage_run row first (FK)
41
+ db.prepare("INSERT INTO pipeline_runs (id, issue_id, issue_title, pipeline_key, repo_url, status, started_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run("p1", "i1", "t", "k", "u", "running", Math.floor(Date.now() / 1000));
42
+ db.prepare("INSERT INTO stage_runs (id, pipeline_run_id, stage, status, started_at) VALUES (?, ?, ?, ?, ?)").run("s1", "p1", "review", "completed", Math.floor(Date.now() / 1000));
43
+ db.prepare("INSERT INTO review_model_runs (id, stage_run_id, provider_id, model_id, status, input_tokens, output_tokens, duration_ms) VALUES (?, ?, ?, ?, ?, ?, ?, ?)").run("r1", "s1", "openrouter", "anthropic/claude-3.5-sonnet", "completed", 100, 50, 1000);
44
+ const rows = db
45
+ .prepare("SELECT * FROM review_model_runs WHERE stage_run_id = ?")
46
+ .all("s1");
47
+ expect(rows).toHaveLength(1);
48
+ });
49
+ });
50
+ describe("insertReviewModelRuns", () => {
51
+ it("writes one row per ReviewModelRun", async () => {
52
+ const sqliteDb = new Database(":memory:");
53
+ runMigrationsSqlite(sqliteDb);
54
+ sqliteDb.prepare("INSERT INTO pipeline_runs (id, issue_id, issue_title, pipeline_key, repo_url, status, started_at) VALUES (?, ?, ?, ?, ?, ?, ?)").run("p1", "i1", "t", "k", "u", "running", Math.floor(Date.now() / 1000));
55
+ sqliteDb.prepare("INSERT INTO stage_runs (id, pipeline_run_id, stage, status, started_at) VALUES (?, ?, ?, ?, ?)").run("s1", "p1", "review", "completed", Math.floor(Date.now() / 1000));
56
+ const db = drizzleSqlite(sqliteDb);
57
+ await insertReviewModelRuns(db, "s1", [
58
+ {
59
+ modelId: "anthropic/claude-3.5-sonnet",
60
+ providerId: "openrouter",
61
+ status: "completed",
62
+ findings: [],
63
+ inputTokens: 100,
64
+ outputTokens: 50,
65
+ durationMs: 1000,
66
+ },
67
+ {
68
+ modelId: "openai/gpt-4o",
69
+ providerId: "openrouter",
70
+ status: "failed",
71
+ findings: [],
72
+ inputTokens: 0,
73
+ outputTokens: 0,
74
+ durationMs: 200,
75
+ errorMessage: "rate limited",
76
+ truncatedFiles: 2,
77
+ },
78
+ ]);
79
+ const rows = sqliteDb
80
+ .prepare("SELECT * FROM review_model_runs WHERE stage_run_id = ? ORDER BY model_id")
81
+ .all("s1");
82
+ expect(rows).toHaveLength(2);
83
+ expect(rows[0].model_id).toBe("anthropic/claude-3.5-sonnet");
84
+ expect(rows[0].input_tokens).toBe(100);
85
+ expect(rows[1].status).toBe("failed");
86
+ expect(rows[1].error_message).toBe("rate limited");
87
+ expect(rows[1].truncated_files).toBe(2);
88
+ });
89
+ });
90
+ //# sourceMappingURL=db-review-model-runs.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db-review-model-runs.test.js","sourceRoot":"","sources":["../../src/__tests__/db-review-model-runs.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,EAAE,mBAAmB,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEtE,QAAQ,CAAC,sCAAsC,EAAE,GAAG,EAAE;IACpD,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QAExB,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,sCAAsC,CAAC;aAC/C,GAAG,EAA6B,CAAC;QACpC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,CAAC,OAAO,CACnB;YACE,cAAc;YACd,aAAa;YACb,eAAe;YACf,IAAI;YACJ,cAAc;YACd,UAAU;YACV,eAAe;YACf,aAAa;YACb,cAAc;YACd,YAAY;YACZ,QAAQ;YACR,iBAAiB;SAClB,CAAC,IAAI,EAAE,CACT,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QACxB,MAAM,OAAO,GAAG,EAAE;aACf,OAAO,CAAC,sCAAsC,CAAC;aAC/C,GAAG,EAA6B,CAAC;QACpC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC1E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wBAAwB,EAAE,GAAG,EAAE;QAChC,MAAM,EAAE,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;QACpC,mBAAmB,CAAC,EAAE,CAAC,CAAC;QAExB,kCAAkC;QAClC,EAAE,CAAC,OAAO,CACR,gIAAgI,CACjI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC3E,EAAE,CAAC,OAAO,CACR,gGAAgG,CACjG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAExE,EAAE,CAAC,OAAO,CACR,2JAA2J,CAC5J,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,EAAE,6BAA6B,EAAE,WAAW,EAAE,GAAG,EAAE,EAAE,EAAE,IAAI,CAAC,CAAC;QAE3F,MAAM,IAAI,GAAG,EAAE;aACZ,OAAO,CAAC,wDAAwD,CAAC;aACjE,GAAG,CAAC,IAAI,CAAC,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC/B,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,mCAAmC,EAAE,KAAK,IAAI,EAAE;QACjD,MAAM,QAAQ,GAAG,IAAI,QAAQ,CAAC,UAAU,CAAC,CAAC;QAC1C,mBAAmB,CAAC,QAAQ,CAAC,CAAC;QAC9B,QAAQ,CAAC,OAAO,CACd,gIAAgI,CACjI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAC3E,QAAQ,CAAC,OAAO,CACd,gGAAgG,CACjG,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,CAAC;QAExE,MAAM,EAAE,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,qBAAqB,CAAC,EAAE,EAAE,IAAI,EAAE;YACpC;gBACE,OAAO,EAAE,6BAA6B;gBACtC,UAAU,EAAE,YAAY;gBACxB,MAAM,EAAE,WAAW;gBACnB,QAAQ,EAAE,EAAE;gBACZ,WAAW,EAAE,GAAG;gBAChB,YAAY,EAAE,EAAE;gBAChB,UAAU,EAAE,IAAI;aACjB;YACD;gBACE,OAAO,EAAE,eAAe;gBACxB,UAAU,EAAE,YAAY;gBACxB,MAAM,EAAE,QAAQ;gBAChB,QAAQ,EAAE,EAAE;gBACZ,WAAW,EAAE,CAAC;gBACd,YAAY,EAAE,CAAC;gBACf,UAAU,EAAE,GAAG;gBACf,YAAY,EAAE,cAAc;gBAC5B,cAAc,EAAE,CAAC;aAClB;SACF,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,QAAQ;aAClB,OAAO,CAAC,0EAA0E,CAAC;aACnF,GAAG,CAAC,IAAI,CAAmC,CAAC;QAC/C,MAAM,CAAC,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,6BAA6B,CAAC,CAAC;QAC7D,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACvC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACnD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * E2E fanout integration test — BEC-134 Task 14
3
+ *
4
+ * Drives `runReviewProviders` end-to-end with:
5
+ * - Real in-memory SQLite DB (better-sqlite3 + runMigrationsSqlite + Drizzle)
6
+ * so actual review_model_runs rows are written and queryable
7
+ * - Mocked OpenRouter HTTP client (avoids network)
8
+ * - Mocked agentic deep-review (avoids Claude SDK)
9
+ *
10
+ * Verifies the four required properties:
11
+ * 1. Both providers (agentic + openrouter) ran
12
+ * 2. review_model_runs rows were persisted for both providers
13
+ * 3. Agentic findings appear in agenticFindings (merge-gate path)
14
+ * 4. Fanout findings do NOT appear in agenticFindings (advisory only)
15
+ */
16
+ export {};
17
+ //# sourceMappingURL=e2e-fanout.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"e2e-fanout.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/e2e-fanout.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG"}