@oneuptime/common 12.0.4 → 12.0.5

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 (374) hide show
  1. package/Models/DatabaseModels/AIRun.ts +38 -1
  2. package/Models/DatabaseModels/AlertFeed.ts +30 -0
  3. package/Models/DatabaseModels/Dashboard.ts +28 -0
  4. package/Models/DatabaseModels/Incident.ts +2 -0
  5. package/Models/DatabaseModels/IncidentEpisode.ts +1 -0
  6. package/Models/DatabaseModels/IncidentEpisodePublicNote.ts +1 -0
  7. package/Models/DatabaseModels/IncidentEpisodeStateTimeline.ts +1 -0
  8. package/Models/DatabaseModels/IncidentFeed.ts +30 -0
  9. package/Models/DatabaseModels/IncidentPublicNote.ts +1 -0
  10. package/Models/DatabaseModels/IncidentStateTimeline.ts +1 -0
  11. package/Models/DatabaseModels/LogSavedView.ts +33 -0
  12. package/Models/DatabaseModels/Project.ts +231 -9
  13. package/Models/DatabaseModels/ScheduledMaintenance.ts +1 -0
  14. package/Models/DatabaseModels/ScheduledMaintenancePublicNote.ts +1 -0
  15. package/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.ts +1 -0
  16. package/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.ts +4 -4
  17. package/Models/DatabaseModels/StatusPage.ts +28 -0
  18. package/Models/DatabaseModels/StatusPageAnnouncement.ts +1 -0
  19. package/Server/API/AIAgentDataAPI.ts +44 -55
  20. package/Server/API/AIInvestigationAPI.ts +175 -17
  21. package/Server/API/DashboardAPI.ts +10 -10
  22. package/Server/API/StatusPageAPI.ts +38 -19
  23. package/Server/EnvironmentConfig.ts +16 -0
  24. package/Server/Infrastructure/ClickhouseConfig.ts +15 -1
  25. package/Server/Infrastructure/ClickhouseDatabase.ts +1 -1
  26. package/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.ts +27 -0
  27. package/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.ts +89 -0
  28. package/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.ts +27 -0
  29. package/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.ts +40 -0
  30. package/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.ts +26 -0
  31. package/Server/Infrastructure/Postgres/SchemaMigrations/Index.ts +10 -0
  32. package/Server/Services/AIRunService.ts +78 -10
  33. package/Server/Services/AIService.ts +94 -22
  34. package/Server/Services/AlertFeedService.ts +5 -0
  35. package/Server/Services/AnalyticsDatabaseService.ts +29 -0
  36. package/Server/Services/DatabaseService.ts +43 -2
  37. package/Server/Services/IncidentFeedService.ts +5 -0
  38. package/Server/Services/LlmLogService.ts +46 -2
  39. package/Server/Utils/AI/Chat/ObservabilityAssistant.ts +6 -0
  40. package/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.ts +4 -0
  41. package/Server/Utils/AI/CodeFix/CodeFixReadiness.ts +8 -5
  42. package/Server/Utils/AI/CodeFix/FixRunBudget.ts +90 -16
  43. package/Server/Utils/AI/Remediation/RemediationExecutionRunner.ts +2 -0
  44. package/Server/Utils/AI/Remediation/RemediationPlanRunner.ts +2 -0
  45. package/Server/Utils/AI/SRE/AIInvestigationEngine.ts +223 -22
  46. package/Server/Utils/AI/SRE/AlertInvestigationRunner.ts +25 -24
  47. package/Server/Utils/AI/SRE/ConfidenceSignal.ts +182 -71
  48. package/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.ts +252 -43
  49. package/Server/Utils/AI/SRE/IncidentInvestigationRunner.ts +25 -24
  50. package/Server/Utils/AI/SRE/InstrumentationTaskTrigger.ts +47 -13
  51. package/Server/Utils/AI/SRE/InvestigationGrader.ts +9 -5
  52. package/Server/Utils/AI/SRE/InvestigationQueue.ts +141 -24
  53. package/Server/Utils/AI/SRE/InvestigationSubjectLock.ts +66 -0
  54. package/Server/Utils/AI/SRE/PostedRootCause.ts +94 -3
  55. package/Server/Utils/AI/SRE/README.md +1 -1
  56. package/Server/Utils/AI/SRE/SubjectCodeFixRun.ts +132 -10
  57. package/Server/Utils/AnalyticsDatabase/ClusterConfig.ts +24 -0
  58. package/Server/Utils/Monitor/Criteria/APIRequestCriteria.ts +29 -0
  59. package/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.ts +56 -0
  60. package/Server/Utils/Monitor/MonitorMetricUtil.ts +46 -0
  61. package/Server/Utils/Monitor/MonitorTemplateUtil.ts +1 -0
  62. package/Server/Utils/PasswordHash.ts +28 -4
  63. package/Tests/App/Dashboard/AIInvestigationHeaderStatus.test.tsx +251 -0
  64. package/Tests/App/Dashboard/EventStatusPanel.test.tsx +747 -0
  65. package/Tests/App/Dashboard/InvestigationFeedRefresh.test.tsx +480 -0
  66. package/Tests/App/Dashboard/InvestigationPanel.test.tsx +1184 -0
  67. package/Tests/App/Dashboard/InvestigationPanelStatus.test.tsx +500 -0
  68. package/Tests/App/Dashboard/PortMonitorCriteriaFilter.test.ts +93 -0
  69. package/Tests/App/StatusPage/PublicStatusPageAPIErrorHandling.test.ts +117 -0
  70. package/Tests/App/StatusPage/StatusPageModelAPIPolymorphism.test.ts +223 -0
  71. package/Tests/Models/DatabaseModels/PermissionCatalogueCoverage.test.ts +243 -0
  72. package/Tests/Server/API/AIAgentDataFixFromIncidentContext.test.ts +266 -0
  73. package/Tests/Server/API/AIInvestigationAPI.test.ts +594 -0
  74. package/Tests/Server/API/AIInvestigationCreateFixTask.test.ts +80 -0
  75. package/Tests/Server/API/DashboardMasterPasswordAPI.test.ts +172 -1
  76. package/Tests/Server/API/StatusPageMasterPasswordAPI.test.ts +335 -0
  77. package/Tests/Server/Services/AIRunCodeFixClaim.test.ts +59 -5
  78. package/Tests/Server/Services/AIRunHumanVerdict.test.ts +127 -58
  79. package/Tests/Server/Services/AIServiceDailyBudget.test.ts +396 -20
  80. package/Tests/Server/Services/AddMasterPasswordSaltMigration.test.ts +283 -0
  81. package/Tests/Server/Services/AnalyticsDatabaseService.test.ts +25 -1
  82. package/Tests/Server/Services/DatabaseServicePerUserPasswordSalt.test.ts +45 -35
  83. package/Tests/Server/Services/DatabaseServiceUpdateColumnsWithoutHooks.test.ts +54 -0
  84. package/Tests/Server/Services/FeedAIRunAssociation.test.ts +125 -0
  85. package/Tests/Server/Services/FixFromIncidentTaskTrigger.test.ts +418 -57
  86. package/Tests/Server/Services/InstrumentationTaskTrigger.test.ts +173 -14
  87. package/Tests/Server/Services/MasterPasswordScrypt.test.ts +567 -0
  88. package/Tests/Server/Services/SeparateIncidentAlertAiSettingsMigration.test.ts +194 -0
  89. package/Tests/Server/Utils/AI/AIAlertGating.test.ts +37 -4
  90. package/Tests/Server/Utils/AI/AIConfidenceSignal.test.ts +330 -29
  91. package/Tests/Server/Utils/AI/AIIncidentGating.test.ts +25 -0
  92. package/Tests/Server/Utils/AI/AIInvestigationQueue.test.ts +293 -5
  93. package/Tests/Server/Utils/AI/CodeFixAgentCompletion.test.ts +59 -1
  94. package/Tests/Server/Utils/AI/FixFromIncidentAutoTrigger.test.ts +342 -19
  95. package/Tests/Server/Utils/AI/FixRunBudget.test.ts +214 -30
  96. package/Tests/Server/Utils/AI/Insights/InvestigationQueueInsightSubject.test.ts +2 -0
  97. package/Tests/Server/Utils/AI/InvestigationGrader.test.ts +65 -17
  98. package/Tests/Server/Utils/AI/InvestigationQueueRemediationExecution.test.ts +3 -0
  99. package/Tests/Server/Utils/AI/InvestigationSettlement.test.ts +313 -20
  100. package/Tests/Server/Utils/AI/PostedRootCause.test.ts +254 -0
  101. package/Tests/Server/Utils/AI/RemediationExecutionRunner.test.ts +4 -0
  102. package/Tests/Server/Utils/AI/RemediationPlanRunner.test.ts +2 -0
  103. package/Tests/Server/Utils/AI/SubjectCodeFixRunDedupe.test.ts +44 -0
  104. package/Tests/Server/Utils/AnalyticsDatabase/ClusterAwareSchema.test.ts +30 -0
  105. package/Tests/Server/Utils/Monitor/Criteria/APIRequestCriteriaPortTimings.test.ts +212 -0
  106. package/Tests/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.test.ts +401 -0
  107. package/Tests/Server/Utils/Monitor/MonitorMetricUtilPortTimings.test.ts +243 -0
  108. package/Tests/Server/Utils/PasswordHash.test.ts +30 -0
  109. package/Tests/Types/Dashboard/DashboardTemplates.test.ts +111 -0
  110. package/Tests/Types/Monitor/CephMetricCatalog.test.ts +104 -0
  111. package/Tests/Types/Monitor/CriteriaFilter.test.ts +4 -0
  112. package/Tests/Types/Monitor/DockerMetricCatalog.test.ts +109 -0
  113. package/Tests/Types/Monitor/DockerSwarmMetricCatalog.test.ts +118 -0
  114. package/Tests/Types/Monitor/HostMetricCatalog.test.ts +104 -0
  115. package/Tests/Types/Monitor/IotMetricCatalog.test.ts +104 -0
  116. package/Tests/Types/Monitor/KubernetesMetricCatalog.test.ts +118 -0
  117. package/Tests/Types/Monitor/MonitorCriteriaInstance.test.ts +42 -0
  118. package/Tests/Types/Monitor/MonitorStep.test.ts +38 -0
  119. package/Tests/Types/Monitor/MonitorStepDomainMonitor.test.ts +75 -0
  120. package/Tests/Types/Monitor/PodmanMetricCatalog.test.ts +109 -0
  121. package/Tests/Types/Monitor/ProxmoxMetricCatalog.test.ts +107 -0
  122. package/Tests/Types/Monitor/SnmpMonitor/SnmpVendorTemplate.test.ts +151 -0
  123. package/Tests/Types/Permission.test.ts +137 -0
  124. package/Tests/Types/Rum/SessionReplayMaskingMode.test.ts +101 -0
  125. package/Tests/UI/Components/AiInvestigationSettingsCard.test.tsx +5 -5
  126. package/Tests/UI/Components/CardModelDetailEdit.test.tsx +3 -5
  127. package/Tests/UI/Components/ErrorBoundary.test.tsx +158 -0
  128. package/Tests/UI/Components/FeedItemSafeMode.test.tsx +74 -0
  129. package/Tests/UI/Components/MoreMenu.test.tsx +756 -0
  130. package/Tests/UI/Components/StatusPage/ResourceGroupSection.test.tsx +62 -0
  131. package/Tests/UI/Monitor/PortMonitorView.test.tsx +237 -0
  132. package/Tests/UI/Telemetry/TelemetrySnapshotWindowAlert.test.tsx +91 -0
  133. package/Tests/UI/Utils/DownloadFile.test.ts +103 -0
  134. package/Tests/UI/Utils/ErrorSupportBundle.test.ts +582 -0
  135. package/Tests/UI/Utils/Project.test.ts +31 -0
  136. package/Tests/UI/Utils/StatusPageModelAPIInjection.test.ts +245 -0
  137. package/Tests/UI/Utils/UseDashboardGridDnd.test.tsx +820 -0
  138. package/Tests/Utils/Dashboard/DashboardViewConfig.test.ts +329 -0
  139. package/Tests/Utils/Dashboard/GridLayout.test.ts +951 -0
  140. package/Tests/Utils/Monitor/MonitorMetricType.test.ts +117 -0
  141. package/Tests/Utils/RecordingRuleExpression.test.ts +327 -0
  142. package/Tests/Utils/StatusPage/GroupNestingLayout.test.ts +186 -0
  143. package/Tests/Utils/StatusPage/GroupTree.test.ts +456 -0
  144. package/Tests/Utils/StatusPage/OverviewGroupHierarchyVisibility.test.ts +588 -0
  145. package/Tests/Utils/Telemetry/SavedViewTimeRange.test.ts +244 -0
  146. package/Tests/Utils/Telemetry/TelemetryQueryTimeRange.test.ts +825 -0
  147. package/Types/AI/AIRunCodeFixRecommendation.ts +17 -0
  148. package/Types/AI/CodeFixTaskContext.ts +63 -3
  149. package/Types/AI/CodeFixTaskType.ts +3 -3
  150. package/Types/HashedString.ts +4 -3
  151. package/Types/Monitor/CriteriaFilter.ts +4 -0
  152. package/Types/Monitor/DomainMonitor/DomainLookupMethod.ts +23 -0
  153. package/Types/Monitor/DomainMonitor/DomainMonitorResponse.ts +7 -0
  154. package/Types/Monitor/MonitorCriteriaInstance.ts +24 -7
  155. package/Types/Monitor/MonitorMetricType.ts +8 -0
  156. package/Types/Monitor/MonitorStep.ts +10 -1
  157. package/Types/Monitor/MonitorStepDomainMonitor.ts +21 -0
  158. package/Types/Monitor/PortMonitor/PortMonitorTimings.ts +10 -0
  159. package/Types/Permission.ts +23 -175
  160. package/Types/Probe/ProbeMonitorResponse.ts +6 -0
  161. package/UI/Components/BulkUpdate/BulkUpdateForm.tsx +2 -3
  162. package/UI/Components/ErrorBoundary.tsx +138 -11
  163. package/UI/Components/Feed/FeedItem.tsx +9 -2
  164. package/UI/Components/ModelDetail/CardModelDetail.tsx +0 -12
  165. package/UI/Components/ModelTable/BaseModelTable.tsx +1 -1
  166. package/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.ts +12 -2
  167. package/UI/Components/MoreMenu/MoreMenu.tsx +285 -97
  168. package/UI/Components/MoreMenu/MoreMenuItem.tsx +8 -5
  169. package/UI/Utils/DownloadFile.ts +16 -8
  170. package/UI/Utils/ErrorSupportBundle.ts +805 -0
  171. package/UI/Utils/ModelAPI/ModelAPI.ts +19 -8
  172. package/UI/Utils/Project.ts +4 -0
  173. package/UI/Utils/StatusPage.ts +8 -2
  174. package/UI/Utils/UseDashboardGridDnd.ts +917 -0
  175. package/Utils/Dashboard/DashboardViewConfig.ts +80 -36
  176. package/Utils/Dashboard/GridLayout.ts +523 -0
  177. package/Utils/Metrics/RecordingRuleExpression.ts +19 -17
  178. package/Utils/Monitor/MonitorMetricType.ts +44 -2
  179. package/Utils/StatusPage/GroupNestingLayout.ts +69 -0
  180. package/Utils/StatusPage/GroupTree.ts +157 -66
  181. package/Utils/StatusPage/ResourceUptime.ts +37 -2
  182. package/Utils/Telemetry/SavedViewTimeRange.ts +114 -0
  183. package/Utils/Telemetry/TelemetryQueryTimeRange.ts +334 -0
  184. package/build/dist/Models/DatabaseModels/AIRun.js +39 -1
  185. package/build/dist/Models/DatabaseModels/AIRun.js.map +1 -1
  186. package/build/dist/Models/DatabaseModels/AlertFeed.js +32 -0
  187. package/build/dist/Models/DatabaseModels/AlertFeed.js.map +1 -1
  188. package/build/dist/Models/DatabaseModels/Dashboard.js +29 -0
  189. package/build/dist/Models/DatabaseModels/Dashboard.js.map +1 -1
  190. package/build/dist/Models/DatabaseModels/Incident.js +2 -0
  191. package/build/dist/Models/DatabaseModels/Incident.js.map +1 -1
  192. package/build/dist/Models/DatabaseModels/IncidentEpisode.js +1 -0
  193. package/build/dist/Models/DatabaseModels/IncidentEpisode.js.map +1 -1
  194. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js +1 -0
  195. package/build/dist/Models/DatabaseModels/IncidentEpisodePublicNote.js.map +1 -1
  196. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js +1 -0
  197. package/build/dist/Models/DatabaseModels/IncidentEpisodeStateTimeline.js.map +1 -1
  198. package/build/dist/Models/DatabaseModels/IncidentFeed.js +32 -0
  199. package/build/dist/Models/DatabaseModels/IncidentFeed.js.map +1 -1
  200. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js +1 -0
  201. package/build/dist/Models/DatabaseModels/IncidentPublicNote.js.map +1 -1
  202. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js +1 -0
  203. package/build/dist/Models/DatabaseModels/IncidentStateTimeline.js.map +1 -1
  204. package/build/dist/Models/DatabaseModels/LogSavedView.js +33 -0
  205. package/build/dist/Models/DatabaseModels/LogSavedView.js.map +1 -1
  206. package/build/dist/Models/DatabaseModels/Project.js +241 -11
  207. package/build/dist/Models/DatabaseModels/Project.js.map +1 -1
  208. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js +1 -0
  209. package/build/dist/Models/DatabaseModels/ScheduledMaintenance.js.map +1 -1
  210. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js +1 -0
  211. package/build/dist/Models/DatabaseModels/ScheduledMaintenancePublicNote.js.map +1 -1
  212. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js +1 -0
  213. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceStateTimeline.js.map +1 -1
  214. package/build/dist/Models/DatabaseModels/ScheduledMaintenanceTemplateOwnerUser.js +4 -4
  215. package/build/dist/Models/DatabaseModels/StatusPage.js +29 -0
  216. package/build/dist/Models/DatabaseModels/StatusPage.js.map +1 -1
  217. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js +1 -0
  218. package/build/dist/Models/DatabaseModels/StatusPageAnnouncement.js.map +1 -1
  219. package/build/dist/Server/API/AIAgentDataAPI.js +28 -46
  220. package/build/dist/Server/API/AIAgentDataAPI.js.map +1 -1
  221. package/build/dist/Server/API/AIInvestigationAPI.js +111 -11
  222. package/build/dist/Server/API/AIInvestigationAPI.js.map +1 -1
  223. package/build/dist/Server/API/DashboardAPI.js +8 -5
  224. package/build/dist/Server/API/DashboardAPI.js.map +1 -1
  225. package/build/dist/Server/API/StatusPageAPI.js +29 -11
  226. package/build/dist/Server/API/StatusPageAPI.js.map +1 -1
  227. package/build/dist/Server/EnvironmentConfig.js +14 -0
  228. package/build/dist/Server/EnvironmentConfig.js.map +1 -1
  229. package/build/dist/Server/Infrastructure/ClickhouseConfig.js +12 -1
  230. package/build/dist/Server/Infrastructure/ClickhouseConfig.js.map +1 -1
  231. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js +1 -1
  232. package/build/dist/Server/Infrastructure/ClickhouseDatabase.js.map +1 -1
  233. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js +22 -0
  234. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786096660558-AddTimeRangeToLogSavedView.js.map +1 -0
  235. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js +36 -0
  236. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786101798351-MigrationName.js.map +1 -0
  237. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js +18 -0
  238. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786105470826-MigrationName.js.map +1 -0
  239. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js +19 -0
  240. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786400000000-AddMasterPasswordSalt.js.map +1 -0
  241. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js +19 -0
  242. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/1786500000000-AddInvestigationCodeFixRecommendation.js.map +1 -0
  243. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js +10 -0
  244. package/build/dist/Server/Infrastructure/Postgres/SchemaMigrations/Index.js.map +1 -1
  245. package/build/dist/Server/Services/AIRunService.js +58 -12
  246. package/build/dist/Server/Services/AIRunService.js.map +1 -1
  247. package/build/dist/Server/Services/AIService.js +74 -21
  248. package/build/dist/Server/Services/AIService.js.map +1 -1
  249. package/build/dist/Server/Services/AlertFeedService.js +3 -0
  250. package/build/dist/Server/Services/AlertFeedService.js.map +1 -1
  251. package/build/dist/Server/Services/AnalyticsDatabaseService.js +29 -1
  252. package/build/dist/Server/Services/AnalyticsDatabaseService.js.map +1 -1
  253. package/build/dist/Server/Services/DatabaseService.js +21 -2
  254. package/build/dist/Server/Services/DatabaseService.js.map +1 -1
  255. package/build/dist/Server/Services/IncidentFeedService.js +3 -0
  256. package/build/dist/Server/Services/IncidentFeedService.js.map +1 -1
  257. package/build/dist/Server/Services/LlmLogService.js +22 -1
  258. package/build/dist/Server/Services/LlmLogService.js.map +1 -1
  259. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js +3 -0
  260. package/build/dist/Server/Utils/AI/Chat/ObservabilityAssistant.js.map +1 -1
  261. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js +4 -0
  262. package/build/dist/Server/Utils/AI/CodeFix/CodeFixAgentCompletion.js.map +1 -1
  263. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js +8 -5
  264. package/build/dist/Server/Utils/AI/CodeFix/CodeFixReadiness.js.map +1 -1
  265. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js +63 -24
  266. package/build/dist/Server/Utils/AI/CodeFix/FixRunBudget.js.map +1 -1
  267. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js +2 -0
  268. package/build/dist/Server/Utils/AI/Remediation/RemediationExecutionRunner.js.map +1 -1
  269. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js +2 -0
  270. package/build/dist/Server/Utils/AI/Remediation/RemediationPlanRunner.js.map +1 -1
  271. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js +156 -28
  272. package/build/dist/Server/Utils/AI/SRE/AIInvestigationEngine.js.map +1 -1
  273. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js +21 -19
  274. package/build/dist/Server/Utils/AI/SRE/AlertInvestigationRunner.js.map +1 -1
  275. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js +128 -49
  276. package/build/dist/Server/Utils/AI/SRE/ConfidenceSignal.js.map +1 -1
  277. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js +170 -31
  278. package/build/dist/Server/Utils/AI/SRE/FixFromIncidentTaskTrigger.js.map +1 -1
  279. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js +21 -19
  280. package/build/dist/Server/Utils/AI/SRE/IncidentInvestigationRunner.js.map +1 -1
  281. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js +33 -9
  282. package/build/dist/Server/Utils/AI/SRE/InstrumentationTaskTrigger.js.map +1 -1
  283. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js +9 -5
  284. package/build/dist/Server/Utils/AI/SRE/InvestigationGrader.js.map +1 -1
  285. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js +121 -41
  286. package/build/dist/Server/Utils/AI/SRE/InvestigationQueue.js.map +1 -1
  287. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js +46 -0
  288. package/build/dist/Server/Utils/AI/SRE/InvestigationSubjectLock.js.map +1 -0
  289. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js +61 -14
  290. package/build/dist/Server/Utils/AI/SRE/PostedRootCause.js.map +1 -1
  291. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js +79 -1
  292. package/build/dist/Server/Utils/AI/SRE/SubjectCodeFixRun.js.map +1 -1
  293. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js +21 -0
  294. package/build/dist/Server/Utils/AnalyticsDatabase/ClusterConfig.js.map +1 -1
  295. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js +20 -3
  296. package/build/dist/Server/Utils/Monitor/Criteria/APIRequestCriteria.js.map +1 -1
  297. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js +43 -0
  298. package/build/dist/Server/Utils/Monitor/Criteria/DomainMonitorCriteria.js.map +1 -1
  299. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js +33 -0
  300. package/build/dist/Server/Utils/Monitor/MonitorMetricUtil.js.map +1 -1
  301. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js +1 -0
  302. package/build/dist/Server/Utils/Monitor/MonitorTemplateUtil.js.map +1 -1
  303. package/build/dist/Server/Utils/PasswordHash.js +25 -4
  304. package/build/dist/Server/Utils/PasswordHash.js.map +1 -1
  305. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js +18 -0
  306. package/build/dist/Types/AI/AIRunCodeFixRecommendation.js.map +1 -0
  307. package/build/dist/Types/AI/CodeFixTaskContext.js +23 -3
  308. package/build/dist/Types/AI/CodeFixTaskContext.js.map +1 -1
  309. package/build/dist/Types/AI/CodeFixTaskType.js +3 -3
  310. package/build/dist/Types/HashedString.js +4 -3
  311. package/build/dist/Types/HashedString.js.map +1 -1
  312. package/build/dist/Types/Monitor/CriteriaFilter.js +4 -0
  313. package/build/dist/Types/Monitor/CriteriaFilter.js.map +1 -1
  314. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js +24 -0
  315. package/build/dist/Types/Monitor/DomainMonitor/DomainLookupMethod.js.map +1 -0
  316. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js +24 -7
  317. package/build/dist/Types/Monitor/MonitorCriteriaInstance.js.map +1 -1
  318. package/build/dist/Types/Monitor/MonitorMetricType.js +7 -0
  319. package/build/dist/Types/Monitor/MonitorMetricType.js.map +1 -1
  320. package/build/dist/Types/Monitor/MonitorStep.js +6 -1
  321. package/build/dist/Types/Monitor/MonitorStep.js.map +1 -1
  322. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js +15 -0
  323. package/build/dist/Types/Monitor/MonitorStepDomainMonitor.js.map +1 -1
  324. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js +2 -0
  325. package/build/dist/Types/Monitor/PortMonitor/PortMonitorTimings.js.map +1 -0
  326. package/build/dist/Types/Permission.js +23 -155
  327. package/build/dist/Types/Permission.js.map +1 -1
  328. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js +2 -5
  329. package/build/dist/UI/Components/BulkUpdate/BulkUpdateForm.js.map +1 -1
  330. package/build/dist/UI/Components/ErrorBoundary.js +67 -8
  331. package/build/dist/UI/Components/ErrorBoundary.js.map +1 -1
  332. package/build/dist/UI/Components/Feed/FeedItem.js +2 -2
  333. package/build/dist/UI/Components/Feed/FeedItem.js.map +1 -1
  334. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js +0 -12
  335. package/build/dist/UI/Components/ModelDetail/CardModelDetail.js.map +1 -1
  336. package/build/dist/UI/Components/ModelTable/BaseModelTable.js +1 -1
  337. package/build/dist/UI/Components/ModelTable/BaseModelTable.js.map +1 -1
  338. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js +12 -2
  339. package/build/dist/UI/Components/MonitorTemplateVariables/TemplateVariablesCatalog.js.map +1 -1
  340. package/build/dist/UI/Components/MoreMenu/MoreMenu.js +193 -65
  341. package/build/dist/UI/Components/MoreMenu/MoreMenu.js.map +1 -1
  342. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js +1 -1
  343. package/build/dist/UI/Components/MoreMenu/MoreMenuItem.js.map +1 -1
  344. package/build/dist/UI/Utils/DownloadFile.js +15 -8
  345. package/build/dist/UI/Utils/DownloadFile.js.map +1 -1
  346. package/build/dist/UI/Utils/ErrorSupportBundle.js +476 -0
  347. package/build/dist/UI/Utils/ErrorSupportBundle.js.map +1 -0
  348. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js +18 -8
  349. package/build/dist/UI/Utils/ModelAPI/ModelAPI.js.map +1 -1
  350. package/build/dist/UI/Utils/Project.js +3 -0
  351. package/build/dist/UI/Utils/Project.js.map +1 -1
  352. package/build/dist/UI/Utils/StatusPage.js +4 -4
  353. package/build/dist/UI/Utils/StatusPage.js.map +1 -1
  354. package/build/dist/UI/Utils/UseDashboardGridDnd.js +551 -0
  355. package/build/dist/UI/Utils/UseDashboardGridDnd.js.map +1 -0
  356. package/build/dist/Utils/Dashboard/DashboardViewConfig.js +42 -26
  357. package/build/dist/Utils/Dashboard/DashboardViewConfig.js.map +1 -1
  358. package/build/dist/Utils/Dashboard/GridLayout.js +338 -0
  359. package/build/dist/Utils/Dashboard/GridLayout.js.map +1 -0
  360. package/build/dist/Utils/Metrics/RecordingRuleExpression.js +19 -17
  361. package/build/dist/Utils/Metrics/RecordingRuleExpression.js.map +1 -1
  362. package/build/dist/Utils/Monitor/MonitorMetricType.js +38 -6
  363. package/build/dist/Utils/Monitor/MonitorMetricType.js.map +1 -1
  364. package/build/dist/Utils/StatusPage/GroupNestingLayout.js +46 -0
  365. package/build/dist/Utils/StatusPage/GroupNestingLayout.js.map +1 -1
  366. package/build/dist/Utils/StatusPage/GroupTree.js +79 -34
  367. package/build/dist/Utils/StatusPage/GroupTree.js.map +1 -1
  368. package/build/dist/Utils/StatusPage/ResourceUptime.js +22 -1
  369. package/build/dist/Utils/StatusPage/ResourceUptime.js.map +1 -1
  370. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js +79 -0
  371. package/build/dist/Utils/Telemetry/SavedViewTimeRange.js.map +1 -0
  372. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js +236 -0
  373. package/build/dist/Utils/Telemetry/TelemetryQueryTimeRange.js.map +1 -0
  374. package/package.json +1 -1
@@ -15,19 +15,24 @@ import AIService, {
15
15
  } from "../../../Server/Services/AIService";
16
16
  import AIInvestigationQueue from "../../../Server/Utils/AI/SRE/InvestigationQueue";
17
17
  import LlmLogService from "../../../Server/Services/LlmLogService";
18
+ import LlmProviderService from "../../../Server/Services/LlmProviderService";
18
19
  import ProjectService from "../../../Server/Services/ProjectService";
19
20
  import AIRunService from "../../../Server/Services/AIRunService";
20
21
  import Project from "../../../Models/DatabaseModels/Project";
22
+ import LlmProvider from "../../../Models/DatabaseModels/LlmProvider";
23
+ import LlmLog from "../../../Models/DatabaseModels/LlmLog";
21
24
  import ObjectID from "../../../Types/ObjectID";
22
25
  import PositiveNumber from "../../../Types/PositiveNumber";
26
+ import LlmType from "../../../Types/LLM/LlmType";
27
+ import LLMService from "../../../Server/Utils/LLM/LLMService";
23
28
  import { describe, expect, test, afterEach } from "@jest/globals";
24
29
 
25
30
  /*
26
- * G4 daily budget: Project.aiDailyAutonomousTokenLimit bounds the tokens the
27
- * AUTONOMOUS_AI_FEATURES may consume per UTC day. The engine skips new
28
- * investigations quietly when the budget is exhausted (no Error run created);
29
- * AIService.executeWithLogging is the hard backstop mid-run. Interactive chat
30
- * is never blocked — its features are not in AUTONOMOUS_AI_FEATURES.
31
+ * G4 daily budget: incident and alert work have independent per-UTC-day token
32
+ * lanes; subjectless work retains Project.aiDailyAutonomousTokenLimit. The
33
+ * engine skips new investigations quietly when its lane is exhausted (no Error
34
+ * run created); AIService.executeWithLogging is the hard backstop mid-run.
35
+ * Interactive chat is never blocked — its features are not autonomous.
31
36
  *
32
37
  * These tests mock the persistence layer and lock in:
33
38
  * (a) no limit configured => never exhausted, and no usage query is run;
@@ -43,6 +48,19 @@ function fakeProject(limit: number | undefined): Project {
43
48
  } as unknown as Project;
44
49
  }
45
50
 
51
+ function fakeProjectWithLaneLimits(data: {
52
+ subjectless?: number | undefined;
53
+ incident?: number | undefined;
54
+ alert?: number | undefined;
55
+ }): Project {
56
+ return {
57
+ id: ObjectID.generate(),
58
+ aiDailyAutonomousTokenLimit: data.subjectless,
59
+ incidentAiDailyAutonomousTokenLimit: data.incident,
60
+ alertAiDailyAutonomousTokenLimit: data.alert,
61
+ } as unknown as Project;
62
+ }
63
+
46
64
  /*
47
65
  * The budget is enforced by matching PERSISTED LlmLog.feature strings against
48
66
  * AUTONOMOUS_AI_FEATURES, so these labels are data, not display text. Changing
@@ -137,6 +155,22 @@ describe("AIService.getAutonomousDailyBudgetStatus", () => {
137
155
  jest.restoreAllMocks();
138
156
  });
139
157
 
158
+ test("rejects a request carrying both subject types before reading project settings", async () => {
159
+ const findProject: jest.SpyInstance = jest.spyOn(
160
+ ProjectService,
161
+ "findOneById",
162
+ );
163
+
164
+ await expect(
165
+ AIService.getAutonomousDailyBudgetStatus(projectId, {
166
+ incidentId: ObjectID.generate(),
167
+ alertId: ObjectID.generate(),
168
+ }),
169
+ ).rejects.toThrow(/both an incident and an alert/);
170
+
171
+ expect(findProject).not.toHaveBeenCalled();
172
+ });
173
+
140
174
  test("no configured limit means never exhausted and no usage query", async () => {
141
175
  jest
142
176
  .spyOn(ProjectService, "findOneById")
@@ -183,6 +217,12 @@ describe("AIService.getAutonomousDailyBudgetStatus", () => {
183
217
  expect(status.exhausted).toBe(false);
184
218
  expect(status.limitInTokens).toBe(100_000);
185
219
  expect(status.usedTokensToday).toBe(99_999);
220
+ expect(LlmLogService.getTotalTokensUsedSince).toHaveBeenCalledWith(
221
+ expect.objectContaining({
222
+ incidentId: undefined,
223
+ alertId: undefined,
224
+ }),
225
+ );
186
226
  });
187
227
 
188
228
  test("usage at the limit is exhausted, scoped to autonomous features", async () => {
@@ -203,6 +243,325 @@ describe("AIService.getAutonomousDailyBudgetStatus", () => {
203
243
  }),
204
244
  );
205
245
  });
246
+
247
+ test("incident work selects the incident limit and incident aggregate lane", async () => {
248
+ const incidentId: ObjectID = ObjectID.generate();
249
+ const findProject: jest.SpyInstance = jest
250
+ .spyOn(ProjectService, "findOneById")
251
+ .mockResolvedValue(
252
+ fakeProjectWithLaneLimits({
253
+ subjectless: 900_000,
254
+ incident: 100_000,
255
+ alert: 200_000,
256
+ }),
257
+ );
258
+ const getTokens: jest.SpyInstance = jest
259
+ .spyOn(LlmLogService, "getTotalTokensUsedSince")
260
+ .mockResolvedValue(99_999);
261
+
262
+ const status: AutonomousBudgetStatus =
263
+ await AIService.getAutonomousDailyBudgetStatus(projectId, { incidentId });
264
+
265
+ expect(status).toEqual({
266
+ exhausted: false,
267
+ limitInTokens: 100_000,
268
+ usedTokensToday: 99_999,
269
+ });
270
+ expect(findProject).toHaveBeenCalledWith(
271
+ expect.objectContaining({
272
+ select: {
273
+ aiDailyAutonomousTokenLimit: true,
274
+ incidentAiDailyAutonomousTokenLimit: true,
275
+ alertAiDailyAutonomousTokenLimit: true,
276
+ },
277
+ }),
278
+ );
279
+ expect(getTokens).toHaveBeenCalledWith(
280
+ expect.objectContaining({
281
+ incidentId,
282
+ alertId: undefined,
283
+ legacyIncidentFeatures: expect.arrayContaining([
284
+ AI_INCIDENT_INVESTIGATION_FEATURE,
285
+ AI_INVESTIGATION_GRADING_FEATURE,
286
+ "Sentinel Incident Investigation",
287
+ "Sentinel Investigation Grading",
288
+ ]),
289
+ legacyAlertFeatures: expect.arrayContaining([
290
+ AI_ALERT_INVESTIGATION_FEATURE,
291
+ "Sentinel Alert Investigation",
292
+ ]),
293
+ }),
294
+ );
295
+ });
296
+
297
+ test("alert work selects the alert limit and alert aggregate lane", async () => {
298
+ const alertId: ObjectID = ObjectID.generate();
299
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue(
300
+ fakeProjectWithLaneLimits({
301
+ subjectless: 900_000,
302
+ incident: 100_000,
303
+ alert: 200_000,
304
+ }),
305
+ );
306
+ const getTokens: jest.SpyInstance = jest
307
+ .spyOn(LlmLogService, "getTotalTokensUsedSince")
308
+ .mockResolvedValue(200_000);
309
+
310
+ const status: AutonomousBudgetStatus =
311
+ await AIService.getAutonomousDailyBudgetStatus(projectId, { alertId });
312
+
313
+ expect(status).toEqual({
314
+ exhausted: true,
315
+ limitInTokens: 200_000,
316
+ usedTokensToday: 200_000,
317
+ });
318
+ expect(getTokens).toHaveBeenCalledWith(
319
+ expect.objectContaining({ incidentId: undefined, alertId }),
320
+ );
321
+ });
322
+
323
+ test("a missing incident limit does not fall back to the legacy subjectless limit", async () => {
324
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue(
325
+ fakeProjectWithLaneLimits({
326
+ subjectless: 1,
327
+ incident: undefined,
328
+ alert: 2,
329
+ }),
330
+ );
331
+ const getTokens: jest.SpyInstance = jest.spyOn(
332
+ LlmLogService,
333
+ "getTotalTokensUsedSince",
334
+ );
335
+
336
+ const status: AutonomousBudgetStatus =
337
+ await AIService.getAutonomousDailyBudgetStatus(projectId, {
338
+ incidentId: ObjectID.generate(),
339
+ });
340
+
341
+ expect(status).toEqual({
342
+ exhausted: false,
343
+ limitInTokens: null,
344
+ usedTokensToday: 0,
345
+ });
346
+ expect(getTokens).not.toHaveBeenCalled();
347
+ });
348
+
349
+ test("one lane can be paused without pausing the other lane", async () => {
350
+ const incidentId: ObjectID = ObjectID.generate();
351
+ const alertId: ObjectID = ObjectID.generate();
352
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue(
353
+ fakeProjectWithLaneLimits({
354
+ subjectless: 0,
355
+ incident: 0,
356
+ alert: 50,
357
+ }),
358
+ );
359
+ const getTokens: jest.SpyInstance = jest
360
+ .spyOn(LlmLogService, "getTotalTokensUsedSince")
361
+ .mockResolvedValue(49);
362
+
363
+ const incidentStatus: AutonomousBudgetStatus =
364
+ await AIService.getAutonomousDailyBudgetStatus(projectId, { incidentId });
365
+ const alertStatus: AutonomousBudgetStatus =
366
+ await AIService.getAutonomousDailyBudgetStatus(projectId, { alertId });
367
+
368
+ expect(incidentStatus.exhausted).toBe(true);
369
+ expect(alertStatus).toEqual({
370
+ exhausted: false,
371
+ limitInTokens: 50,
372
+ usedTokensToday: 49,
373
+ });
374
+ expect(getTokens).toHaveBeenCalledTimes(1);
375
+ expect(getTokens).toHaveBeenCalledWith(
376
+ expect.objectContaining({ incidentId: undefined, alertId }),
377
+ );
378
+ });
379
+ });
380
+
381
+ describe("LlmLogService autonomous-token lane isolation", () => {
382
+ type QueryCall = [string, Array<unknown>];
383
+
384
+ afterEach(() => {
385
+ jest.restoreAllMocks();
386
+ });
387
+
388
+ function mockTokenQuery(): jest.Mock {
389
+ const query: jest.Mock = jest.fn().mockResolvedValue([{ total: "17" }]);
390
+ jest.spyOn(LlmLogService, "getRepository").mockReturnValue({
391
+ manager: { query },
392
+ } as any);
393
+ return query;
394
+ }
395
+
396
+ async function aggregateFor(data: {
397
+ incidentId?: ObjectID | undefined;
398
+ alertId?: ObjectID | undefined;
399
+ }): Promise<string> {
400
+ const query: jest.Mock = mockTokenQuery();
401
+
402
+ await LlmLogService.getTotalTokensUsedSince({
403
+ projectId: ObjectID.generate(),
404
+ since: new Date("2026-08-07T00:00:00.000Z"),
405
+ features: [AI_INCIDENT_INVESTIGATION_FEATURE],
406
+ ...data,
407
+ });
408
+
409
+ const [sql] = query.mock.calls[0] as QueryCall;
410
+ return sql;
411
+ }
412
+
413
+ test("incident aggregates include only incident-linked logs", async () => {
414
+ const sql: string = await aggregateFor({
415
+ incidentId: ObjectID.generate(),
416
+ });
417
+
418
+ expect(sql).toContain('"incidentId" IS NOT NULL');
419
+ expect(sql).toContain('"alertId" IS NULL');
420
+ });
421
+
422
+ test("alert aggregates include only alert-linked logs", async () => {
423
+ const sql: string = await aggregateFor({ alertId: ObjectID.generate() });
424
+
425
+ expect(sql).toContain('"incidentId" IS NULL');
426
+ expect(sql).toContain('"alertId" IS NOT NULL');
427
+ });
428
+
429
+ test("subjectless aggregates require both subject ids to be null", async () => {
430
+ const sql: string = await aggregateFor({});
431
+
432
+ expect(sql).toContain(
433
+ '"log"."incidentId" IS NULL AND "log"."alertId" IS NULL',
434
+ );
435
+ });
436
+
437
+ test("legacy rows are attributed by feature or their linked AI run", async () => {
438
+ const query: jest.Mock = mockTokenQuery();
439
+ const legacyIncidentFeatures: Array<string> = [
440
+ AI_INCIDENT_INVESTIGATION_FEATURE,
441
+ ];
442
+ const legacyAlertFeatures: Array<string> = [AI_ALERT_INVESTIGATION_FEATURE];
443
+
444
+ await LlmLogService.getTotalTokensUsedSince({
445
+ projectId: ObjectID.generate(),
446
+ since: new Date("2026-08-07T00:00:00.000Z"),
447
+ features: AUTONOMOUS_AI_FEATURES,
448
+ incidentId: ObjectID.generate(),
449
+ legacyIncidentFeatures,
450
+ legacyAlertFeatures,
451
+ });
452
+
453
+ const [sql, params] = query.mock.calls[0] as QueryCall;
454
+ expect(sql).toContain('"log"."feature" = ANY($4)');
455
+ expect(sql).toContain('FROM "AIRun" AS "run"');
456
+ expect(sql).toContain('"run"."triggeredByIncidentId" IS NOT NULL');
457
+ expect(params[3]).toEqual(legacyIncidentFeatures);
458
+ expect(params[4]).toEqual(legacyAlertFeatures);
459
+ });
460
+
461
+ test("subjectless totals exclude identifiable legacy incident and alert rows", async () => {
462
+ const query: jest.Mock = mockTokenQuery();
463
+
464
+ await LlmLogService.getTotalTokensUsedSince({
465
+ projectId: ObjectID.generate(),
466
+ since: new Date("2026-08-07T00:00:00.000Z"),
467
+ features: AUTONOMOUS_AI_FEATURES,
468
+ legacyIncidentFeatures: [AI_INCIDENT_INVESTIGATION_FEATURE],
469
+ legacyAlertFeatures: [AI_ALERT_INVESTIGATION_FEATURE],
470
+ });
471
+
472
+ const [sql] = query.mock.calls[0] as QueryCall;
473
+ expect(sql).toContain('NOT ("log"."feature" = ANY($4))');
474
+ expect(sql).toContain('NOT ("log"."feature" = ANY($5))');
475
+ expect(sql).toContain('NOT (EXISTS (SELECT 1 FROM "AIRun" AS "run"');
476
+ });
477
+
478
+ test("rejects a dual-lane aggregate before running SQL", async () => {
479
+ const query: jest.Mock = mockTokenQuery();
480
+
481
+ await expect(
482
+ LlmLogService.getTotalTokensUsedSince({
483
+ projectId: ObjectID.generate(),
484
+ since: new Date("2026-08-07T00:00:00.000Z"),
485
+ features: [AI_INCIDENT_INVESTIGATION_FEATURE],
486
+ incidentId: ObjectID.generate(),
487
+ alertId: ObjectID.generate(),
488
+ }),
489
+ ).rejects.toThrow(/both the incident and alert lanes/);
490
+
491
+ expect(query).not.toHaveBeenCalled();
492
+ });
493
+ });
494
+
495
+ describe("AIService.executeWithLogging autonomous lane forwarding", () => {
496
+ afterEach(() => {
497
+ jest.restoreAllMocks();
498
+ });
499
+
500
+ test("rejects dual-subject logging before resolving a provider", async () => {
501
+ const getProvider: jest.SpyInstance = jest.spyOn(
502
+ LlmProviderService,
503
+ "getProviderForChat",
504
+ );
505
+
506
+ await expect(
507
+ AIService.executeWithLogging({
508
+ projectId: ObjectID.generate(),
509
+ incidentId: ObjectID.generate(),
510
+ alertId: ObjectID.generate(),
511
+ feature: AI_INCIDENT_INVESTIGATION_FEATURE,
512
+ messages: [{ role: "user", content: "investigate" }],
513
+ }),
514
+ ).rejects.toThrow(/both an incident and an alert/);
515
+
516
+ expect(getProvider).not.toHaveBeenCalled();
517
+ });
518
+
519
+ test("forwards subject identity to the hard budget backstop", async () => {
520
+ const projectId: ObjectID = ObjectID.generate();
521
+ const incidentId: ObjectID = ObjectID.generate();
522
+ const aiRunId: ObjectID = ObjectID.generate();
523
+ jest.spyOn(LlmProviderService, "getProviderForChat").mockResolvedValue({
524
+ id: ObjectID.generate(),
525
+ llmType: LlmType.OpenAI,
526
+ isGlobalLlm: false,
527
+ } as unknown as LlmProvider);
528
+ const budget: jest.SpyInstance = jest
529
+ .spyOn(AIService, "getAutonomousDailyBudgetStatus")
530
+ .mockResolvedValue({
531
+ exhausted: false,
532
+ limitInTokens: 1_000,
533
+ usedTokensToday: 10,
534
+ });
535
+ jest.spyOn(LLMService, "getCompletion").mockResolvedValue({
536
+ content: "done",
537
+ usage: { totalTokens: 1 },
538
+ } as Awaited<ReturnType<typeof LLMService.getCompletion>>);
539
+ const createLog: jest.SpyInstance = jest
540
+ .spyOn(LlmLogService, "create")
541
+ .mockResolvedValue(new LlmLog());
542
+
543
+ await AIService.executeWithLogging({
544
+ projectId,
545
+ incidentId,
546
+ aiRunId,
547
+ feature: AI_INCIDENT_INVESTIGATION_FEATURE,
548
+ messages: [{ role: "user", content: "investigate" }],
549
+ });
550
+
551
+ expect(budget).toHaveBeenCalledWith(projectId, {
552
+ incidentId,
553
+ alertId: undefined,
554
+ });
555
+ expect(createLog).toHaveBeenCalledWith(
556
+ expect.objectContaining({
557
+ data: expect.objectContaining({
558
+ incidentId,
559
+ alertId: undefined,
560
+ aiRunId,
561
+ }),
562
+ }),
563
+ );
564
+ });
206
565
  });
207
566
 
208
567
  describe("AIInvestigationQueue budget skip", () => {
@@ -211,19 +570,27 @@ describe("AIInvestigationQueue budget skip", () => {
211
570
  });
212
571
 
213
572
  test("does not enqueue when the daily budget is exhausted", async () => {
214
- jest.spyOn(AIService, "getAutonomousDailyBudgetStatus").mockResolvedValue({
215
- exhausted: true,
216
- limitInTokens: 100_000,
217
- usedTokensToday: 120_000,
218
- });
573
+ const budget: jest.SpyInstance = jest
574
+ .spyOn(AIService, "getAutonomousDailyBudgetStatus")
575
+ .mockResolvedValue({
576
+ exhausted: true,
577
+ limitInTokens: 100_000,
578
+ usedTokensToday: 120_000,
579
+ });
219
580
  const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
581
+ const projectId: ObjectID = ObjectID.generate();
582
+ const alertId: ObjectID = ObjectID.generate();
220
583
 
221
584
  await AIInvestigationQueue.enqueue({
222
- projectId: ObjectID.generate(),
223
- subjectAlertId: ObjectID.generate(),
585
+ projectId,
586
+ subjectAlertId: alertId,
224
587
  });
225
588
 
226
589
  expect(create).not.toHaveBeenCalled();
590
+ expect(budget).toHaveBeenCalledWith(projectId, {
591
+ incidentId: undefined,
592
+ alertId,
593
+ });
227
594
  });
228
595
 
229
596
  test("does not enqueue when the budget check itself fails", async () => {
@@ -241,7 +608,7 @@ describe("AIInvestigationQueue budget skip", () => {
241
608
  });
242
609
 
243
610
  test("leaves a queued run unclaimed when the budget is exhausted at claim time", async () => {
244
- // No per-project cap override; concurrency cap passes…
611
+ // No alert-lane cap override; concurrency cap passes…
245
612
  jest
246
613
  .spyOn(ProjectService, "findOneById")
247
614
  .mockResolvedValue(fakeProject(undefined));
@@ -249,23 +616,32 @@ describe("AIInvestigationQueue budget skip", () => {
249
616
  .spyOn(AIRunService, "countBy")
250
617
  .mockResolvedValue(new PositiveNumber(0));
251
618
  // …but the budget is exhausted.
252
- jest.spyOn(AIService, "getAutonomousDailyBudgetStatus").mockResolvedValue({
253
- exhausted: true,
254
- limitInTokens: 100_000,
255
- usedTokensToday: 120_000,
256
- });
619
+ const budget: jest.SpyInstance = jest
620
+ .spyOn(AIService, "getAutonomousDailyBudgetStatus")
621
+ .mockResolvedValue({
622
+ exhausted: true,
623
+ limitInTokens: 100_000,
624
+ usedTokensToday: 120_000,
625
+ });
257
626
  const claim: jest.SpyInstance = jest.spyOn(
258
627
  AIRunService,
259
628
  "attemptStatusTransition",
260
629
  );
261
630
 
631
+ const projectId: ObjectID = ObjectID.generate();
632
+ const alertId: ObjectID = ObjectID.generate();
633
+
262
634
  await AIInvestigationQueue.processRun({
263
635
  id: ObjectID.generate(),
264
- projectId: ObjectID.generate(),
636
+ projectId,
265
637
  attemptCount: 0,
266
- triggeredByAlertId: ObjectID.generate(),
638
+ triggeredByAlertId: alertId,
267
639
  });
268
640
 
269
641
  expect(claim).not.toHaveBeenCalled();
642
+ expect(budget).toHaveBeenCalledWith(projectId, {
643
+ incidentId: undefined,
644
+ alertId,
645
+ });
270
646
  });
271
647
  });