@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
@@ -4,6 +4,7 @@ import FixRunBudget, {
4
4
  } from "../../../../Server/Utils/AI/CodeFix/FixRunBudget";
5
5
  import ProjectService from "../../../../Server/Services/ProjectService";
6
6
  import AIRunService from "../../../../Server/Services/AIRunService";
7
+ import QueryHelper from "../../../../Server/Types/Database/QueryHelper";
7
8
  import Project from "../../../../Models/DatabaseModels/Project";
8
9
  import AIRunType from "../../../../Types/AI/AIRunType";
9
10
  import BadDataException from "../../../../Types/Exception/BadDataException";
@@ -12,11 +13,11 @@ import PositiveNumber from "../../../../Types/PositiveNumber";
12
13
  import { describe, expect, test, afterEach } from "@jest/globals";
13
14
 
14
15
  /*
15
- * The per-project daily fix-run budget (G11 guardrail): every CodeFix
16
- * AIRun counts against Project.aiDailyFixTaskLimit per UTC day. Unlike the
17
- * token budget, an UNSET limit is NOT unlimited — fix runs open pull
16
+ * The per-project daily fix-run budget (G11 guardrail): incident, alert and
17
+ * subjectless CodeFix AIRuns each count only against their own lane. Unlike
18
+ * the token budget, an UNSET limit is NOT unlimited — fix runs open pull
18
19
  * requests on customer repositories, so the default cap applies. 0 pauses
19
- * fix tasks entirely (the same kill-switch semantics as the token budget).
20
+ * that lane entirely (the same kill-switch semantics as the token budget).
20
21
  */
21
22
 
22
23
  const projectId: ObjectID = ObjectID.generate();
@@ -92,24 +93,37 @@ describe("FixRunBudget.evaluate (pure decision)", () => {
92
93
  });
93
94
 
94
95
  describe("FixRunBudget.describeRejection", () => {
95
- test("paused rejection names the setting and the 0 value", () => {
96
+ test("paused incident rejection names the incident setting and destination", () => {
96
97
  const message: string = FixRunBudget.describeRejection(
97
98
  FixRunBudget.evaluate({ configuredLimit: 0, runsToday: 0 }),
99
+ { incidentId: ObjectID.generate() },
98
100
  );
99
101
 
100
- expect(message).toMatch(/Daily AI Fix Task Limit/);
102
+ expect(message).toMatch(/Daily Incident AI Fix Task Limit/);
103
+ expect(message).toMatch(/Incidents > Settings > AI/);
101
104
  expect(message).toMatch(/0/);
102
105
  });
103
106
 
104
- test("over-budget rejection names the counts, the setting and the default", () => {
107
+ test("over-budget alert rejection names the alert setting and destination", () => {
105
108
  const message: string = FixRunBudget.describeRejection(
106
109
  FixRunBudget.evaluate({ configuredLimit: 10, runsToday: 10 }),
110
+ { alertId: ObjectID.generate() },
107
111
  );
108
112
 
109
113
  expect(message).toMatch(/10 of 10/);
110
- expect(message).toMatch(/Daily AI Fix Task Limit/);
114
+ expect(message).toMatch(/Daily Alert AI Fix Task Limit/);
115
+ expect(message).toMatch(/Alerts > Settings > AI/);
111
116
  expect(message).toMatch(new RegExp(String(DEFAULT_DAILY_FIX_RUN_LIMIT)));
112
117
  });
118
+
119
+ test("subjectless rejection points to the always-visible AI Guardrails page", () => {
120
+ const message: string = FixRunBudget.describeRejection(
121
+ FixRunBudget.evaluate({ configuredLimit: 0, runsToday: 0 }),
122
+ );
123
+
124
+ expect(message).toMatch(/Daily Other AI Fix Task Limit/);
125
+ expect(message).toMatch(/Project Settings > AI > AI Guardrails/);
126
+ });
113
127
  });
114
128
 
115
129
  describe("FixRunBudget.getBudgetStatus (IO wiring)", () => {
@@ -117,12 +131,46 @@ describe("FixRunBudget.getBudgetStatus (IO wiring)", () => {
117
131
  jest.restoreAllMocks();
118
132
  });
119
133
 
120
- test("counts the project's CodeFix runs created since UTC midnight", async () => {
121
- jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
122
- id: projectId,
123
- aiDailyFixTaskLimit: 10,
124
- } as unknown as Project);
134
+ function mockSubjectOperators(): {
135
+ isNull: Record<string, string>;
136
+ notNull: Record<string, string>;
137
+ } {
138
+ const isNull: Record<string, string> = { operator: "is-null" };
139
+ const notNull: Record<string, string> = { operator: "not-null" };
140
+
141
+ jest.spyOn(QueryHelper, "isNull").mockReturnValue(isNull);
142
+ jest.spyOn(QueryHelper, "notNull").mockReturnValue(notNull);
125
143
 
144
+ return { isNull, notNull };
145
+ }
146
+
147
+ test("rejects a run carrying both subject types before reading project settings", async () => {
148
+ const findProject: jest.SpyInstance = jest.spyOn(
149
+ ProjectService,
150
+ "findOneById",
151
+ );
152
+
153
+ await expect(
154
+ FixRunBudget.getBudgetStatus(projectId, {
155
+ incidentId: ObjectID.generate(),
156
+ alertId: ObjectID.generate(),
157
+ }),
158
+ ).rejects.toThrow(/both an incident and an alert/);
159
+
160
+ expect(findProject).not.toHaveBeenCalled();
161
+ });
162
+
163
+ test("subjectless callers retain the fallback limit and count only subjectless CodeFix runs", async () => {
164
+ const operators: ReturnType<typeof mockSubjectOperators> =
165
+ mockSubjectOperators();
166
+ const findProject: jest.SpyInstance = jest
167
+ .spyOn(ProjectService, "findOneById")
168
+ .mockResolvedValue({
169
+ id: projectId,
170
+ aiDailyFixTaskLimit: 10,
171
+ incidentAiDailyFixTaskLimit: 1,
172
+ alertAiDailyFixTaskLimit: 2,
173
+ } as unknown as Project);
126
174
  const countBy: jest.SpyInstance = jest
127
175
  .spyOn(AIRunService, "countBy")
128
176
  .mockResolvedValue(new PositiveNumber(4));
@@ -136,44 +184,180 @@ describe("FixRunBudget.getBudgetStatus (IO wiring)", () => {
136
184
  paused: false,
137
185
  runsToday: 4,
138
186
  });
187
+ expect(findProject).toHaveBeenCalledWith(
188
+ expect.objectContaining({ select: { aiDailyFixTaskLimit: true } }),
189
+ );
190
+
191
+ const query: Record<string, unknown> = (
192
+ countBy.mock.calls[0]![0] as { query: Record<string, unknown> }
193
+ ).query;
194
+ expect(query["projectId"]).toBe(projectId);
195
+ expect(query["runType"]).toBe(AIRunType.CodeFix);
196
+ expect(query["triggeredByIncidentId"]).toBe(operators.isNull);
197
+ expect(query["triggeredByAlertId"]).toBe(operators.isNull);
198
+ // createdAt >= UTC midnight rides in a QueryHelper find operator.
199
+ expect(query["createdAt"]).toBeDefined();
200
+ });
201
+
202
+ test("an explicitly empty subject from SubjectCodeFixRun also stays in the subjectless lane", async () => {
203
+ const operators: ReturnType<typeof mockSubjectOperators> =
204
+ mockSubjectOperators();
205
+ const findProject: jest.SpyInstance = jest
206
+ .spyOn(ProjectService, "findOneById")
207
+ .mockResolvedValue({
208
+ id: projectId,
209
+ aiDailyFixTaskLimit: 3,
210
+ incidentAiDailyFixTaskLimit: 0,
211
+ alertAiDailyFixTaskLimit: 0,
212
+ } as unknown as Project);
213
+ const countBy: jest.SpyInstance = jest
214
+ .spyOn(AIRunService, "countBy")
215
+ .mockResolvedValue(new PositiveNumber(2));
216
+
217
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
218
+ projectId,
219
+ { incidentId: undefined, alertId: undefined },
220
+ );
221
+
222
+ expect(decision.limit).toBe(3);
223
+ expect(decision.allowed).toBe(true);
224
+ expect(findProject).toHaveBeenCalledWith(
225
+ expect.objectContaining({ select: { aiDailyFixTaskLimit: true } }),
226
+ );
227
+
228
+ const query: Record<string, unknown> = (
229
+ countBy.mock.calls[0]![0] as { query: Record<string, unknown> }
230
+ ).query;
231
+ expect(query["triggeredByIncidentId"]).toBe(operators.isNull);
232
+ expect(query["triggeredByAlertId"]).toBe(operators.isNull);
233
+ });
234
+
235
+ test("incident callers select the incident limit and count only incident CodeFix runs", async () => {
236
+ const operators: ReturnType<typeof mockSubjectOperators> =
237
+ mockSubjectOperators();
238
+ const findProject: jest.SpyInstance = jest
239
+ .spyOn(ProjectService, "findOneById")
240
+ .mockResolvedValue({
241
+ id: projectId,
242
+ aiDailyFixTaskLimit: 99,
243
+ incidentAiDailyFixTaskLimit: 5,
244
+ alertAiDailyFixTaskLimit: 1,
245
+ } as unknown as Project);
246
+ const countBy: jest.SpyInstance = jest
247
+ .spyOn(AIRunService, "countBy")
248
+ .mockResolvedValue(new PositiveNumber(4));
249
+
250
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
251
+ projectId,
252
+ { incidentId: ObjectID.generate() },
253
+ );
139
254
 
140
- expect(countBy).toHaveBeenCalledWith(
255
+ expect(decision).toEqual({
256
+ allowed: true,
257
+ limit: 5,
258
+ paused: false,
259
+ runsToday: 4,
260
+ });
261
+ expect(findProject).toHaveBeenCalledWith(
141
262
  expect.objectContaining({
142
- query: expect.objectContaining({
143
- projectId,
144
- runType: AIRunType.CodeFix,
145
- // createdAt >= UTC midnight rides in a QueryHelper find operator.
146
- createdAt: expect.anything(),
147
- }),
148
- props: expect.objectContaining({ isRoot: true }),
263
+ select: { incidentAiDailyFixTaskLimit: true },
149
264
  }),
150
265
  );
266
+
267
+ const query: Record<string, unknown> = (
268
+ countBy.mock.calls[0]![0] as { query: Record<string, unknown> }
269
+ ).query;
270
+ expect(query["runType"]).toBe(AIRunType.CodeFix);
271
+ expect(query["triggeredByIncidentId"]).toBe(operators.notNull);
272
+ expect(query["triggeredByAlertId"]).toBe(operators.isNull);
151
273
  });
152
274
 
153
- test("a paused project (limit 0) short-circuits without the count query", async () => {
275
+ test("alert callers select the alert limit and count only alert CodeFix runs", async () => {
276
+ const operators: ReturnType<typeof mockSubjectOperators> =
277
+ mockSubjectOperators();
278
+ const findProject: jest.SpyInstance = jest
279
+ .spyOn(ProjectService, "findOneById")
280
+ .mockResolvedValue({
281
+ id: projectId,
282
+ aiDailyFixTaskLimit: 99,
283
+ incidentAiDailyFixTaskLimit: 1,
284
+ alertAiDailyFixTaskLimit: 7,
285
+ } as unknown as Project);
286
+ const countBy: jest.SpyInstance = jest
287
+ .spyOn(AIRunService, "countBy")
288
+ .mockResolvedValue(new PositiveNumber(6));
289
+
290
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
291
+ projectId,
292
+ { alertId: ObjectID.generate() },
293
+ );
294
+
295
+ expect(decision).toEqual({
296
+ allowed: true,
297
+ limit: 7,
298
+ paused: false,
299
+ runsToday: 6,
300
+ });
301
+ expect(findProject).toHaveBeenCalledWith(
302
+ expect.objectContaining({ select: { alertAiDailyFixTaskLimit: true } }),
303
+ );
304
+
305
+ const query: Record<string, unknown> = (
306
+ countBy.mock.calls[0]![0] as { query: Record<string, unknown> }
307
+ ).query;
308
+ expect(query["runType"]).toBe(AIRunType.CodeFix);
309
+ expect(query["triggeredByIncidentId"]).toBe(operators.isNull);
310
+ expect(query["triggeredByAlertId"]).toBe(operators.notNull);
311
+ });
312
+
313
+ test("pausing the incident lane short-circuits without counting another lane", async () => {
154
314
  jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
155
315
  id: projectId,
156
- aiDailyFixTaskLimit: 0,
316
+ aiDailyFixTaskLimit: 50,
317
+ incidentAiDailyFixTaskLimit: 0,
318
+ alertAiDailyFixTaskLimit: 50,
157
319
  } as unknown as Project);
320
+ const countBy: jest.SpyInstance = jest.spyOn(AIRunService, "countBy");
321
+
322
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
323
+ projectId,
324
+ { incidentId: ObjectID.generate() },
325
+ );
326
+
327
+ expect(decision.allowed).toBe(false);
328
+ expect(decision.paused).toBe(true);
329
+ expect(countBy).not.toHaveBeenCalled();
330
+ });
158
331
 
332
+ test("pausing the alert lane short-circuits without counting another lane", async () => {
333
+ jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
334
+ id: projectId,
335
+ aiDailyFixTaskLimit: 50,
336
+ incidentAiDailyFixTaskLimit: 50,
337
+ alertAiDailyFixTaskLimit: 0,
338
+ } as unknown as Project);
159
339
  const countBy: jest.SpyInstance = jest.spyOn(AIRunService, "countBy");
160
340
 
161
- const decision: FixRunBudgetDecision =
162
- await FixRunBudget.getBudgetStatus(projectId);
341
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
342
+ projectId,
343
+ { alertId: ObjectID.generate() },
344
+ );
163
345
 
164
346
  expect(decision.allowed).toBe(false);
165
347
  expect(decision.paused).toBe(true);
166
348
  expect(countBy).not.toHaveBeenCalled();
167
349
  });
168
350
 
169
- test("a missing project row falls back to the default cap (fail-safe, not fail-open)", async () => {
351
+ test("a missing project row uses the default cap in the requested lane (fail-safe, not fail-open)", async () => {
170
352
  jest.spyOn(ProjectService, "findOneById").mockResolvedValue(null);
171
353
  jest
172
354
  .spyOn(AIRunService, "countBy")
173
355
  .mockResolvedValue(new PositiveNumber(DEFAULT_DAILY_FIX_RUN_LIMIT));
174
356
 
175
- const decision: FixRunBudgetDecision =
176
- await FixRunBudget.getBudgetStatus(projectId);
357
+ const decision: FixRunBudgetDecision = await FixRunBudget.getBudgetStatus(
358
+ projectId,
359
+ { alertId: ObjectID.generate() },
360
+ );
177
361
 
178
362
  expect(decision.limit).toBe(DEFAULT_DAILY_FIX_RUN_LIMIT);
179
363
  expect(decision.allowed).toBe(false);
@@ -199,7 +383,7 @@ describe("FixRunBudget.assertWithinBudget", () => {
199
383
  ).resolves.toBeUndefined();
200
384
  });
201
385
 
202
- test("over budget throws a BadDataException naming the setting", async () => {
386
+ test("over budget throws a BadDataException naming the subjectless setting", async () => {
203
387
  jest.spyOn(ProjectService, "findOneById").mockResolvedValue({
204
388
  id: projectId,
205
389
  aiDailyFixTaskLimit: 5,
@@ -212,7 +396,7 @@ describe("FixRunBudget.assertWithinBudget", () => {
212
396
  BadDataException,
213
397
  );
214
398
  await expect(FixRunBudget.assertWithinBudget(projectId)).rejects.toThrow(
215
- /Daily AI Fix Task Limit/,
399
+ /Daily Other AI Fix Task Limit/,
216
400
  );
217
401
  });
218
402
  });
@@ -8,6 +8,7 @@ import AIService from "../../../../../Server/Services/AIService";
8
8
  import ProjectService from "../../../../../Server/Services/ProjectService";
9
9
  import Project from "../../../../../Models/DatabaseModels/Project";
10
10
  import AIRun from "../../../../../Models/DatabaseModels/AIRun";
11
+ import AIRunCodeFixRecommendation from "../../../../../Types/AI/AIRunCodeFixRecommendation";
11
12
  import AIRunStatus from "../../../../../Types/AI/AIRunStatus";
12
13
  import AIRunType from "../../../../../Types/AI/AIRunType";
13
14
  import ObjectID from "../../../../../Types/ObjectID";
@@ -76,6 +77,7 @@ describe("AIInvestigationQueue — insight subject", () => {
76
77
  data: expect.objectContaining({
77
78
  status: AIRunStatus.Queued,
78
79
  triggeredByAiInsightId: insightId,
80
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
79
81
  }),
80
82
  props: expect.objectContaining({ isRoot: true }),
81
83
  }),
@@ -1,13 +1,12 @@
1
1
  import InvestigationGrader from "../../../../Server/Utils/AI/SRE/InvestigationGrader";
2
+ import PostedRootCause from "../../../../Server/Utils/AI/SRE/PostedRootCause";
2
3
  import AIRunService from "../../../../Server/Services/AIRunService";
3
4
  import IncidentService from "../../../../Server/Services/IncidentService";
4
- import IncidentFeedService from "../../../../Server/Services/IncidentFeedService";
5
5
  import AIService, {
6
6
  AILogResponse,
7
7
  } from "../../../../Server/Services/AIService";
8
8
  import AIRun from "../../../../Models/DatabaseModels/AIRun";
9
9
  import Incident from "../../../../Models/DatabaseModels/Incident";
10
- import IncidentFeed from "../../../../Models/DatabaseModels/IncidentFeed";
11
10
  import AIRunAutoGrade from "../../../../Types/AI/AIRunAutoGrade";
12
11
  import ObjectID from "../../../../Types/ObjectID";
13
12
  import { describe, expect, test, afterEach } from "@jest/globals";
@@ -24,19 +23,20 @@ import { describe, expect, test, afterEach } from "@jest/globals";
24
23
 
25
24
  const incidentId: ObjectID = ObjectID.generate();
26
25
  const projectId: ObjectID = ObjectID.generate();
26
+ const runCompletedAt: Date = new Date("2026-08-07T12:00:00.000Z");
27
27
 
28
28
  function fakeRun(autoGrade?: AIRunAutoGrade): AIRun {
29
- return { id: ObjectID.generate(), autoGrade } as unknown as AIRun;
29
+ return {
30
+ id: ObjectID.generate(),
31
+ autoGrade,
32
+ completedAt: runCompletedAt,
33
+ } as unknown as AIRun;
30
34
  }
31
35
 
32
36
  function fakeIncident(rootCause?: string | undefined): Incident {
33
37
  return { id: incidentId, rootCause } as unknown as Incident;
34
38
  }
35
39
 
36
- function fakeFeedItem(markdown: string): IncidentFeed {
37
- return { feedInfoInMarkdown: markdown } as unknown as IncidentFeed;
38
- }
39
-
40
40
  function fakeLlmResponse(content: string): AILogResponse {
41
41
  return { content } as unknown as AILogResponse;
42
42
  }
@@ -221,11 +221,14 @@ describe("InvestigationGrader.gradeInvestigationOnResolve", () => {
221
221
  });
222
222
 
223
223
  test("no posted analysis (no RootCause feed item) → no LLM call", async () => {
224
- jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(fakeRun());
224
+ const run: AIRun = fakeRun();
225
+ jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
225
226
  jest
226
227
  .spyOn(IncidentService, "findOneById")
227
228
  .mockResolvedValue(fakeIncident("db down"));
228
- jest.spyOn(IncidentFeedService, "findOneBy").mockResolvedValue(null);
229
+ const getForInvestigation: jest.SpyInstance = jest
230
+ .spyOn(PostedRootCause, "getForInvestigation")
231
+ .mockResolvedValue(null);
229
232
  const executeWithLogging: jest.SpyInstance = jest.spyOn(
230
233
  AIService,
231
234
  "executeWithLogging",
@@ -236,9 +239,56 @@ describe("InvestigationGrader.gradeInvestigationOnResolve", () => {
236
239
  projectId,
237
240
  });
238
241
 
242
+ expect(getForInvestigation).toHaveBeenCalledWith({
243
+ incidentId,
244
+ aiRunId: run.id,
245
+ runCompletedAt,
246
+ });
239
247
  expect(executeWithLogging).not.toHaveBeenCalled();
240
248
  });
241
249
 
250
+ test("reads the report associated with the selected completed run exactly", async () => {
251
+ const run: AIRun = fakeRun();
252
+ const selectedAnalysis: string =
253
+ "## Selected investigation\nThe selected run found pool exhaustion.";
254
+ jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
255
+ jest
256
+ .spyOn(IncidentService, "findOneById")
257
+ .mockResolvedValue(fakeIncident("The connection pool was exhausted."));
258
+ const getForInvestigation: jest.SpyInstance = jest
259
+ .spyOn(PostedRootCause, "getForInvestigation")
260
+ .mockResolvedValue(selectedAnalysis);
261
+ const executeWithLogging: jest.SpyInstance = jest
262
+ .spyOn(AIService, "executeWithLogging")
263
+ .mockResolvedValue(fakeLlmResponse("MATCH"));
264
+ jest
265
+ .spyOn(AIRunService, "updateOneById")
266
+ .mockResolvedValue(undefined as never);
267
+
268
+ await InvestigationGrader.gradeInvestigationOnResolve({
269
+ incidentId,
270
+ projectId,
271
+ });
272
+
273
+ expect(getForInvestigation).toHaveBeenCalledTimes(1);
274
+ expect(getForInvestigation).toHaveBeenCalledWith({
275
+ incidentId,
276
+ aiRunId: run.id,
277
+ runCompletedAt,
278
+ });
279
+ expect(executeWithLogging).toHaveBeenCalledWith(
280
+ expect.objectContaining({
281
+ aiRunId: run.id,
282
+ messages: expect.arrayContaining([
283
+ expect.objectContaining({
284
+ role: "user",
285
+ content: expect.stringContaining(selectedAnalysis),
286
+ }),
287
+ ]),
288
+ }),
289
+ );
290
+ });
291
+
242
292
  test("happy path: one budgeted, preview-less LLM call; grade + timestamp stored on the run", async () => {
243
293
  const run: AIRun = fakeRun();
244
294
  jest.spyOn(AIRunService, "findOneBy").mockResolvedValue(run);
@@ -246,10 +296,8 @@ describe("InvestigationGrader.gradeInvestigationOnResolve", () => {
246
296
  .spyOn(IncidentService, "findOneById")
247
297
  .mockResolvedValue(fakeIncident("The connection pool was exhausted."));
248
298
  jest
249
- .spyOn(IncidentFeedService, "findOneBy")
250
- .mockResolvedValue(
251
- fakeFeedItem("## Analysis\nThe db connection pool ran dry."),
252
- );
299
+ .spyOn(PostedRootCause, "getForInvestigation")
300
+ .mockResolvedValue("## Analysis\nThe db connection pool ran dry.");
253
301
  const executeWithLogging: jest.SpyInstance = jest
254
302
  .spyOn(AIService, "executeWithLogging")
255
303
  .mockResolvedValue(fakeLlmResponse("MATCH"));
@@ -297,8 +345,8 @@ describe("InvestigationGrader.gradeInvestigationOnResolve", () => {
297
345
  .spyOn(IncidentService, "findOneById")
298
346
  .mockResolvedValue(fakeIncident("db down"));
299
347
  jest
300
- .spyOn(IncidentFeedService, "findOneBy")
301
- .mockResolvedValue(fakeFeedItem("Analysis text."));
348
+ .spyOn(PostedRootCause, "getForInvestigation")
349
+ .mockResolvedValue("Analysis text.");
302
350
  jest
303
351
  .spyOn(AIService, "executeWithLogging")
304
352
  .mockResolvedValue(fakeLlmResponse("Either MATCH or MISMATCH."));
@@ -321,8 +369,8 @@ describe("InvestigationGrader.gradeInvestigationOnResolve", () => {
321
369
  .spyOn(IncidentService, "findOneById")
322
370
  .mockResolvedValue(fakeIncident("db down"));
323
371
  jest
324
- .spyOn(IncidentFeedService, "findOneBy")
325
- .mockResolvedValue(fakeFeedItem("Analysis text."));
372
+ .spyOn(PostedRootCause, "getForInvestigation")
373
+ .mockResolvedValue("Analysis text.");
326
374
  jest
327
375
  .spyOn(AIService, "executeWithLogging")
328
376
  .mockRejectedValue(new Error("provider down"));
@@ -5,6 +5,7 @@ import AIService from "../../../../Server/Services/AIService";
5
5
  import ProjectService from "../../../../Server/Services/ProjectService";
6
6
  import AIRun from "../../../../Models/DatabaseModels/AIRun";
7
7
  import Project from "../../../../Models/DatabaseModels/Project";
8
+ import AIRunCodeFixRecommendation from "../../../../Types/AI/AIRunCodeFixRecommendation";
8
9
  import AIRunStatus from "../../../../Types/AI/AIRunStatus";
9
10
  import AIRunType from "../../../../Types/AI/AIRunType";
10
11
  import ObjectID from "../../../../Types/ObjectID";
@@ -96,6 +97,7 @@ describe("AIInvestigationQueue — RemediationExecution runs", () => {
96
97
  status: AIRunStatus.Queued,
97
98
  runType: AIRunType.RemediationExecution,
98
99
  triggeredByAutoRemediationSuggestionId: SUGGESTION_ID,
100
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
99
101
  // Incident linkage stays set for the dashboard.
100
102
  triggeredByIncidentId: INCIDENT_ID,
101
103
  }),
@@ -131,6 +133,7 @@ describe("AIInvestigationQueue — RemediationExecution runs", () => {
131
133
  data: expect.objectContaining({
132
134
  runType: AIRunType.RemediationPlan,
133
135
  triggeredByAutoRemediationSuggestionId: SUGGESTION_ID,
136
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
134
137
  }),
135
138
  }),
136
139
  );