@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
@@ -10,6 +10,7 @@ import IncidentFeed, {
10
10
  import SortOrder from "../../../../Types/BaseDatabase/SortOrder";
11
11
  import ObjectID from "../../../../Types/ObjectID";
12
12
  import { afterEach, describe, expect, it } from "@jest/globals";
13
+ import { FindOperator } from "typeorm";
13
14
 
14
15
  /*
15
16
  * The one reader of the analysis an AI investigation posted.
@@ -31,6 +32,9 @@ const INCIDENT_ID: ObjectID = new ObjectID(
31
32
  "cccccccc-cccc-4ccc-8ccc-cccccccccccc",
32
33
  );
33
34
  const ALERT_ID: ObjectID = new ObjectID("dddddddd-dddd-4ddd-8ddd-dddddddddddd");
35
+ const AI_RUN_ID: ObjectID = new ObjectID(
36
+ "eeeeeeee-eeee-4eee-8eee-eeeeeeeeeeee",
37
+ );
34
38
 
35
39
  function incidentFeedItem(markdown: string | null): IncidentFeed {
36
40
  return {
@@ -44,6 +48,23 @@ function alertFeedItem(markdown: string | null): AlertFeed {
44
48
  } as unknown as AlertFeed;
45
49
  }
46
50
 
51
+ interface RawFindOperatorInternals {
52
+ _getSql: (columnName: string) => string;
53
+ _objectLiteralParameters: Record<string, unknown>;
54
+ }
55
+
56
+ function expectCreatedAtCutoff(
57
+ createdAtFilter: unknown,
58
+ expectedCutoff: Date,
59
+ ): void {
60
+ expect(createdAtFilter).toBeInstanceOf(FindOperator);
61
+
62
+ const raw: RawFindOperatorInternals =
63
+ createdAtFilter as RawFindOperatorInternals;
64
+ expect(raw._getSql("COLUMN")).toContain("COLUMN >=");
65
+ expect(Object.values(raw._objectLiteralParameters)).toEqual([expectedCutoff]);
66
+ }
67
+
47
68
  describe("PostedRootCause.getForIncident", () => {
48
69
  afterEach(() => {
49
70
  jest.restoreAllMocks();
@@ -85,6 +106,73 @@ describe("PostedRootCause.getForIncident", () => {
85
106
  }),
86
107
  }),
87
108
  );
109
+ const query: Record<string, unknown> = find.mock.calls[0]![0]
110
+ .query as Record<string, unknown>;
111
+ expect(Object.prototype.hasOwnProperty.call(query, "createdAt")).toBe(
112
+ false,
113
+ );
114
+ expect(Object.prototype.hasOwnProperty.call(query, "aiRunId")).toBe(false);
115
+ });
116
+
117
+ it("can select the RootCause explicitly owned by one investigation run", async () => {
118
+ const find: jest.SpyInstance = jest
119
+ .spyOn(IncidentFeedService, "findOneBy")
120
+ .mockResolvedValue(null);
121
+
122
+ await PostedRootCause.getForIncident(INCIDENT_ID, {
123
+ aiRunId: AI_RUN_ID,
124
+ });
125
+
126
+ expect(find).toHaveBeenCalledWith(
127
+ expect.objectContaining({
128
+ query: expect.objectContaining({
129
+ incidentId: INCIDENT_ID,
130
+ incidentFeedEventType: IncidentFeedEventType.RootCause,
131
+ aiRunId: AI_RUN_ID,
132
+ }),
133
+ }),
134
+ );
135
+ });
136
+
137
+ it("can restrict an upgrade lookup to rows without an AI run association", async () => {
138
+ const find: jest.SpyInstance = jest
139
+ .spyOn(IncidentFeedService, "findOneBy")
140
+ .mockResolvedValue(null);
141
+
142
+ await PostedRootCause.getForIncident(INCIDENT_ID, {
143
+ withoutAIRunId: true,
144
+ });
145
+
146
+ const aiRunIdFilter: unknown = find.mock.calls[0]![0].query.aiRunId;
147
+ expect(aiRunIdFilter).toBeInstanceOf(FindOperator);
148
+ expect(
149
+ (aiRunIdFilter as RawFindOperatorInternals)._getSql("COLUMN"),
150
+ ).toContain("COLUMN IS NULL");
151
+ });
152
+
153
+ it("can scope the RootCause item to feed rows created by this run", async () => {
154
+ const runCompletedAt: Date = new Date("2026-08-07T10:00:00.000Z");
155
+ const find: jest.SpyInstance = jest
156
+ .spyOn(IncidentFeedService, "findOneBy")
157
+ .mockResolvedValue(null);
158
+
159
+ await PostedRootCause.getForIncident(INCIDENT_ID, {
160
+ createdAtOrAfter: runCompletedAt,
161
+ });
162
+
163
+ expect(find).toHaveBeenCalledWith(
164
+ expect.objectContaining({
165
+ query: expect.objectContaining({
166
+ incidentId: INCIDENT_ID,
167
+ incidentFeedEventType: IncidentFeedEventType.RootCause,
168
+ createdAt: expect.any(FindOperator),
169
+ }),
170
+ }),
171
+ );
172
+ expectCreatedAtCutoff(
173
+ find.mock.calls[0]![0].query.createdAt,
174
+ runCompletedAt,
175
+ );
88
176
  });
89
177
 
90
178
  it("returns null when no analysis has been posted", async () => {
@@ -166,6 +254,57 @@ describe("PostedRootCause.getForAlert", () => {
166
254
  }),
167
255
  }),
168
256
  );
257
+ const query: Record<string, unknown> = find.mock.calls[0]![0]
258
+ .query as Record<string, unknown>;
259
+ expect(Object.prototype.hasOwnProperty.call(query, "createdAt")).toBe(
260
+ false,
261
+ );
262
+ expect(Object.prototype.hasOwnProperty.call(query, "aiRunId")).toBe(false);
263
+ });
264
+
265
+ it("can select the RootCause explicitly owned by one alert investigation", async () => {
266
+ const find: jest.SpyInstance = jest
267
+ .spyOn(AlertFeedService, "findOneBy")
268
+ .mockResolvedValue(null);
269
+
270
+ await PostedRootCause.getForAlert(ALERT_ID, {
271
+ aiRunId: AI_RUN_ID,
272
+ });
273
+
274
+ expect(find).toHaveBeenCalledWith(
275
+ expect.objectContaining({
276
+ query: expect.objectContaining({
277
+ alertId: ALERT_ID,
278
+ alertFeedEventType: AlertFeedEventType.RootCause,
279
+ aiRunId: AI_RUN_ID,
280
+ }),
281
+ }),
282
+ );
283
+ });
284
+
285
+ it("can scope the RootCause item to alert feed rows created by this run", async () => {
286
+ const runCompletedAt: Date = new Date("2026-08-07T11:00:00.000Z");
287
+ const find: jest.SpyInstance = jest
288
+ .spyOn(AlertFeedService, "findOneBy")
289
+ .mockResolvedValue(null);
290
+
291
+ await PostedRootCause.getForAlert(ALERT_ID, {
292
+ createdAtOrAfter: runCompletedAt,
293
+ });
294
+
295
+ expect(find).toHaveBeenCalledWith(
296
+ expect.objectContaining({
297
+ query: expect.objectContaining({
298
+ alertId: ALERT_ID,
299
+ alertFeedEventType: AlertFeedEventType.RootCause,
300
+ createdAt: expect.any(FindOperator),
301
+ }),
302
+ }),
303
+ );
304
+ expectCreatedAtCutoff(
305
+ find.mock.calls[0]![0].query.createdAt,
306
+ runCompletedAt,
307
+ );
169
308
  });
170
309
 
171
310
  it("returns null when no analysis has been posted", async () => {
@@ -196,6 +335,43 @@ describe("PostedRootCause.getForSubject", () => {
196
335
  expect(alertFind).not.toHaveBeenCalled();
197
336
  });
198
337
 
338
+ it("forwards the run boundary to the subject-specific reader", async () => {
339
+ const runCompletedAt: Date = new Date("2026-08-07T12:00:00.000Z");
340
+ const getForIncident: jest.SpyInstance = jest
341
+ .spyOn(PostedRootCause, "getForIncident")
342
+ .mockResolvedValue("current analysis");
343
+
344
+ expect(
345
+ await PostedRootCause.getForSubject({
346
+ incidentId: INCIDENT_ID,
347
+ createdAtOrAfter: runCompletedAt,
348
+ }),
349
+ ).toBe("current analysis");
350
+ expect(getForIncident).toHaveBeenCalledWith(INCIDENT_ID, {
351
+ aiRunId: undefined,
352
+ withoutAIRunId: undefined,
353
+ createdAtOrAfter: runCompletedAt,
354
+ });
355
+ });
356
+
357
+ it("forwards the exact run id to the subject-specific reader", async () => {
358
+ const getForAlert: jest.SpyInstance = jest
359
+ .spyOn(PostedRootCause, "getForAlert")
360
+ .mockResolvedValue("current alert analysis");
361
+
362
+ expect(
363
+ await PostedRootCause.getForSubject({
364
+ alertId: ALERT_ID,
365
+ aiRunId: AI_RUN_ID,
366
+ }),
367
+ ).toBe("current alert analysis");
368
+ expect(getForAlert).toHaveBeenCalledWith(ALERT_ID, {
369
+ aiRunId: AI_RUN_ID,
370
+ withoutAIRunId: undefined,
371
+ createdAtOrAfter: undefined,
372
+ });
373
+ });
374
+
199
375
  it("reads the alert feed for an alert subject", async () => {
200
376
  const alertFind: jest.SpyInstance = jest
201
377
  .spyOn(AlertFeedService, "findOneBy")
@@ -252,3 +428,81 @@ describe("PostedRootCause.getForSubject", () => {
252
428
  expect(alertFind).not.toHaveBeenCalled();
253
429
  });
254
430
  });
431
+
432
+ describe("PostedRootCause.getForInvestigation", () => {
433
+ afterEach(() => {
434
+ jest.restoreAllMocks();
435
+ });
436
+
437
+ it("returns the exact run-associated report without a legacy lookup", async () => {
438
+ const getForSubject: jest.SpyInstance = jest
439
+ .spyOn(PostedRootCause, "getForSubject")
440
+ .mockResolvedValue("exact report");
441
+
442
+ expect(
443
+ await PostedRootCause.getForInvestigation({
444
+ incidentId: INCIDENT_ID,
445
+ aiRunId: AI_RUN_ID,
446
+ }),
447
+ ).toBe("exact report");
448
+ expect(getForSubject).toHaveBeenCalledTimes(1);
449
+ expect(getForSubject).toHaveBeenCalledWith({
450
+ incidentId: INCIDENT_ID,
451
+ alertId: undefined,
452
+ aiRunId: AI_RUN_ID,
453
+ });
454
+ });
455
+
456
+ it("recovers a branded null-associated report across a deployment-safe upgrade window", async () => {
457
+ const runCompletedAt: Date = new Date("2026-08-08T10:00:00.000Z");
458
+ const legacyReport: string =
459
+ "## AI — Automated Root Cause Analysis\n\nHistorical evidence.";
460
+ const getForSubject: jest.SpyInstance = jest
461
+ .spyOn(PostedRootCause, "getForSubject")
462
+ .mockResolvedValueOnce(null)
463
+ .mockResolvedValueOnce(legacyReport);
464
+
465
+ expect(
466
+ await PostedRootCause.getForInvestigation({
467
+ alertId: ALERT_ID,
468
+ aiRunId: AI_RUN_ID,
469
+ runCompletedAt,
470
+ }),
471
+ ).toBe(legacyReport);
472
+ expect(getForSubject).toHaveBeenNthCalledWith(2, {
473
+ incidentId: undefined,
474
+ alertId: ALERT_ID,
475
+ withoutAIRunId: true,
476
+ createdAtOrAfter: runCompletedAt,
477
+ });
478
+ });
479
+
480
+ it("rejects ordinary RootCause markdown from the legacy path", async () => {
481
+ jest
482
+ .spyOn(PostedRootCause, "getForSubject")
483
+ .mockResolvedValueOnce(null)
484
+ .mockResolvedValueOnce("## Root cause\n\nWritten by an engineer.");
485
+
486
+ expect(
487
+ await PostedRootCause.getForInvestigation({
488
+ incidentId: INCIDENT_ID,
489
+ aiRunId: AI_RUN_ID,
490
+ runCompletedAt: new Date("2026-08-08T10:00:00.000Z"),
491
+ }),
492
+ ).toBeNull();
493
+ });
494
+
495
+ it("never falls back to an unassociated row without a reliable completion boundary", async () => {
496
+ const getForSubject: jest.SpyInstance = jest
497
+ .spyOn(PostedRootCause, "getForSubject")
498
+ .mockResolvedValue(null);
499
+
500
+ expect(
501
+ await PostedRootCause.getForInvestigation({
502
+ incidentId: INCIDENT_ID,
503
+ aiRunId: AI_RUN_ID,
504
+ }),
505
+ ).toBeNull();
506
+ expect(getForSubject).toHaveBeenCalledTimes(1);
507
+ });
508
+ });
@@ -547,6 +547,8 @@ describe("RemediationExecutionRunner.executeRemediation", () => {
547
547
  );
548
548
  // Persisted budget-ledger string — pinned as a literal on purpose.
549
549
  expect(request.get().feature).toBe("AI Remediation Execution");
550
+ expect(request.get().incidentId).toBe(INCIDENT_ID);
551
+ expect(request.get().alertId).toBeUndefined();
550
552
  });
551
553
 
552
554
  it("runs FullAuto with the execute tool and the allowlist in context when every condition holds", async () => {
@@ -859,6 +861,8 @@ describe("RemediationExecutionRunner.executeRemediation", () => {
859
861
  '<untrusted_context source="alert_text">',
860
862
  );
861
863
  expect(captured!.contextSummary).toContain("Disk almost full on db-1");
864
+ expect(captured!.incidentId).toBeUndefined();
865
+ expect(captured!.alertId).toBe(ALERT_ID);
862
866
  expect(incidentFeed).not.toHaveBeenCalled();
863
867
  expect(alertFeed).toHaveBeenCalledWith(
864
868
  expect.objectContaining({
@@ -260,6 +260,8 @@ describe("RemediationPlanRunner.executePlan", () => {
260
260
  request: expect.objectContaining({
261
261
  // Persisted budget-ledger string — pinned as a literal on purpose.
262
262
  feature: "AI Remediation Planning",
263
+ incidentId: INCIDENT_ID,
264
+ alertId: undefined,
263
265
  }),
264
266
  }),
265
267
  );
@@ -1,4 +1,5 @@
1
1
  import SubjectCodeFixRun from "../../../../Server/Utils/AI/SRE/SubjectCodeFixRun";
2
+ import FixRunBudget from "../../../../Server/Utils/AI/CodeFix/FixRunBudget";
2
3
  import AIRunService from "../../../../Server/Services/AIRunService";
3
4
  import QueryHelper from "../../../../Server/Types/Database/QueryHelper";
4
5
  import AIRun from "../../../../Models/DatabaseModels/AIRun";
@@ -119,6 +120,27 @@ describe("SubjectCodeFixRun dedupe guards", () => {
119
120
  });
120
121
 
121
122
  describe("findNonTerminalRunForSubject", () => {
123
+ test.each([
124
+ { label: "neither", input: {} },
125
+ { label: "both", input: { incidentId, alertId } },
126
+ ])(
127
+ "rejects $label subject type before querying",
128
+ async ({
129
+ input,
130
+ }: {
131
+ input: { incidentId?: ObjectID; alertId?: ObjectID };
132
+ }) => {
133
+ await expect(
134
+ SubjectCodeFixRun.findNonTerminalRunForSubject({
135
+ taskType: CodeFixTaskType.FixFromIncident,
136
+ ...input,
137
+ }),
138
+ ).rejects.toThrow(/Exactly one/);
139
+
140
+ expect(AIRunService.findOneBy).not.toHaveBeenCalled();
141
+ },
142
+ );
143
+
122
144
  test("a NoFixFound run does NOT block a new run for the same subject", async () => {
123
145
  storeRun(AIRunStatus.NoFixFound);
124
146
 
@@ -176,6 +198,28 @@ describe("SubjectCodeFixRun dedupe guards", () => {
176
198
  });
177
199
  });
178
200
 
201
+ describe("enqueueSubjectCodeFixRun", () => {
202
+ test("rejects a dual-subject run before the budget check or write", async () => {
203
+ const assertWithinBudget: jest.SpyInstance = jest.spyOn(
204
+ FixRunBudget,
205
+ "assertWithinBudget",
206
+ );
207
+ const create: jest.SpyInstance = jest.spyOn(AIRunService, "create");
208
+
209
+ await expect(
210
+ SubjectCodeFixRun.enqueueSubjectCodeFixRun({
211
+ projectId,
212
+ taskType: CodeFixTaskType.FixFromIncident,
213
+ incidentId,
214
+ alertId,
215
+ }),
216
+ ).rejects.toThrow(/both an incident and an alert/);
217
+
218
+ expect(assertWithinBudget).not.toHaveBeenCalled();
219
+ expect(create).not.toHaveBeenCalled();
220
+ });
221
+ });
222
+
179
223
  describe("findNonTerminalPerformanceFixRunForTrace", () => {
180
224
  test("a NoFixFound run does NOT block a new run for the same trace", async () => {
181
225
  storeRun(AIRunStatus.NoFixFound);
@@ -8,6 +8,7 @@ import {
8
8
  adaptTableSettingsForStorage,
9
9
  applyClusterToMaterializedViewQuery,
10
10
  getClickhouseClusterName,
11
+ getDistributedDdlTaskTimeoutSeconds,
11
12
  getDistributedEngine,
12
13
  getStorageEngine,
13
14
  getStorageTableName,
@@ -33,6 +34,8 @@ import MetricBaselineHourly from "../../../../Models/AnalyticsModels/MetricBasel
33
34
 
34
35
  const CLUSTER_ENV_KEY: string = "CLICKHOUSE_CLUSTER_NAME";
35
36
  const SHARDING_ENV_KEY: string = "CLICKHOUSE_SHARDING_KEY";
37
+ const DDL_TIMEOUT_ENV_KEY: string =
38
+ "CLICKHOUSE_DISTRIBUTED_DDL_TASK_TIMEOUT_SECONDS";
36
39
 
37
40
  /*
38
41
  * Flatten a Statement into a single string (raw SQL + serialized identifier
@@ -49,6 +52,8 @@ function fullText(statement: Statement | string): string {
49
52
  describe("ClickHouse cluster-aware schema (always-on)", () => {
50
53
  const originalCluster: string | undefined = process.env[CLUSTER_ENV_KEY];
51
54
  const originalSharding: string | undefined = process.env[SHARDING_ENV_KEY];
55
+ const originalDdlTimeout: string | undefined =
56
+ process.env[DDL_TIMEOUT_ENV_KEY];
52
57
 
53
58
  afterEach(() => {
54
59
  if (originalCluster === undefined) {
@@ -61,6 +66,11 @@ describe("ClickHouse cluster-aware schema (always-on)", () => {
61
66
  } else {
62
67
  process.env[SHARDING_ENV_KEY] = originalSharding;
63
68
  }
69
+ if (originalDdlTimeout === undefined) {
70
+ delete process.env[DDL_TIMEOUT_ENV_KEY];
71
+ } else {
72
+ process.env[DDL_TIMEOUT_ENV_KEY] = originalDdlTimeout;
73
+ }
64
74
  });
65
75
 
66
76
  describe("ClusterConfig helpers", () => {
@@ -101,6 +111,26 @@ describe("ClickHouse cluster-aware schema (always-on)", () => {
101
111
  );
102
112
  });
103
113
 
114
+ test("distributed DDL task timeout: default 180, overridable, garbage-safe", () => {
115
+ delete process.env[DDL_TIMEOUT_ENV_KEY];
116
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(180);
117
+
118
+ process.env[DDL_TIMEOUT_ENV_KEY] = "1800";
119
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(1800);
120
+
121
+ // ClickHouse semantics pass through: 0 = async, negative = no server cap.
122
+ process.env[DDL_TIMEOUT_ENV_KEY] = "0";
123
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(0);
124
+ process.env[DDL_TIMEOUT_ENV_KEY] = "-1";
125
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(-1);
126
+
127
+ // Garbage and whitespace fall back to the default.
128
+ process.env[DDL_TIMEOUT_ENV_KEY] = "not-a-number";
129
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(180);
130
+ process.env[DDL_TIMEOUT_ENV_KEY] = " ";
131
+ expect(getDistributedDdlTaskTimeoutSeconds()).toBe(180);
132
+ });
133
+
104
134
  test("distributed engine: model key, with global override winning", () => {
105
135
  delete process.env[SHARDING_ENV_KEY];
106
136
  // model sharding key is used
@@ -0,0 +1,212 @@
1
+ import APIRequestCriteria from "../../../../../Server/Utils/Monitor/Criteria/APIRequestCriteria";
2
+ import EvaluateOverTime from "../../../../../Server/Utils/Monitor/Criteria/EvaluateOverTime";
3
+ import {
4
+ CheckOn,
5
+ CriteriaFilter,
6
+ EvaluateOverTimeType,
7
+ FilterType,
8
+ } from "../../../../../Types/Monitor/CriteriaFilter";
9
+ import PortMonitorTimings from "../../../../../Types/Monitor/PortMonitor/PortMonitorTimings";
10
+ import ProbeMonitorResponse from "../../../../../Types/Probe/ProbeMonitorResponse";
11
+ import ObjectID from "../../../../../Types/ObjectID";
12
+ import { afterEach, describe, expect, jest, test } from "@jest/globals";
13
+
14
+ function buildResponse(portTimings?: PortMonitorTimings): ProbeMonitorResponse {
15
+ return {
16
+ projectId: ObjectID.generate(),
17
+ monitorId: ObjectID.generate(),
18
+ monitorStepId: ObjectID.generate(),
19
+ probeId: ObjectID.generate(),
20
+ failureCause: "",
21
+ monitoredAt: new Date(),
22
+ portTimings: portTimings,
23
+ };
24
+ }
25
+
26
+ function criteria(input: {
27
+ checkOn: CheckOn.PortDnsLookupTime | CheckOn.PortTcpConnectTime;
28
+ filterType?: FilterType;
29
+ value: number | string;
30
+ evaluateOverTime?: boolean;
31
+ }): CriteriaFilter {
32
+ return {
33
+ checkOn: input.checkOn,
34
+ filterType: input.filterType || FilterType.GreaterThan,
35
+ value: input.value,
36
+ evaluateOverTime: input.evaluateOverTime,
37
+ evaluateOverTimeOptions: input.evaluateOverTime
38
+ ? {
39
+ timeValueInMinutes: 5,
40
+ evaluateOverTimeType: EvaluateOverTimeType.Average,
41
+ }
42
+ : undefined,
43
+ };
44
+ }
45
+
46
+ async function evaluate(
47
+ response: ProbeMonitorResponse,
48
+ criteriaFilter: CriteriaFilter,
49
+ ): Promise<string | null> {
50
+ return APIRequestCriteria.isMonitorInstanceCriteriaFilterMet({
51
+ dataToProcess: response,
52
+ criteriaFilter: criteriaFilter,
53
+ });
54
+ }
55
+
56
+ describe("APIRequestCriteria Port connection phase timings", () => {
57
+ afterEach(() => {
58
+ jest.restoreAllMocks();
59
+ });
60
+
61
+ test("evaluates the current DNS lookup duration", async () => {
62
+ const result: string | null = await evaluate(
63
+ buildResponse({
64
+ dnsLookupInMs: 151,
65
+ tcpConnectInMs: 25,
66
+ totalConnectionInMs: 176,
67
+ }),
68
+ criteria({ checkOn: CheckOn.PortDnsLookupTime, value: "150" }),
69
+ );
70
+
71
+ expect(result).toContain(CheckOn.PortDnsLookupTime);
72
+ });
73
+
74
+ test("returns null when the current DNS lookup duration is below the threshold", async () => {
75
+ const result: string | null = await evaluate(
76
+ buildResponse({
77
+ dnsLookupInMs: 149,
78
+ tcpConnectInMs: 25,
79
+ totalConnectionInMs: 174,
80
+ }),
81
+ criteria({ checkOn: CheckOn.PortDnsLookupTime, value: 150 }),
82
+ );
83
+
84
+ expect(result).toBeNull();
85
+ });
86
+
87
+ test("evaluates the current TCP connect duration independently of DNS", async () => {
88
+ const result: string | null = await evaluate(
89
+ buildResponse({
90
+ dnsLookupInMs: 300,
91
+ tcpConnectInMs: 75,
92
+ totalConnectionInMs: 375,
93
+ }),
94
+ criteria({
95
+ checkOn: CheckOn.PortTcpConnectTime,
96
+ filterType: FilterType.GreaterThanOrEqualTo,
97
+ value: 75,
98
+ }),
99
+ );
100
+
101
+ expect(result).toContain(CheckOn.PortTcpConnectTime);
102
+ });
103
+
104
+ test("treats an absent DNS phase on an IP-literal destination as no data", async () => {
105
+ const result: string | null = await evaluate(
106
+ buildResponse({ tcpConnectInMs: 20, totalConnectionInMs: 20 }),
107
+ criteria({
108
+ checkOn: CheckOn.PortDnsLookupTime,
109
+ filterType: FilterType.LessThan,
110
+ value: 100,
111
+ }),
112
+ );
113
+
114
+ expect(result).toBeNull();
115
+ });
116
+
117
+ test("treats an absent TCP phase on a failed pre-connect check as no data", async () => {
118
+ const result: string | null = await evaluate(
119
+ buildResponse({ dnsLookupInMs: 100, totalConnectionInMs: 100 }),
120
+ criteria({ checkOn: CheckOn.PortTcpConnectTime, value: 10 }),
121
+ );
122
+
123
+ expect(result).toBeNull();
124
+ });
125
+
126
+ test("preserves a legitimate zero-millisecond phase", async () => {
127
+ const result: string | null = await evaluate(
128
+ buildResponse({
129
+ dnsLookupInMs: 0,
130
+ tcpConnectInMs: 0,
131
+ totalConnectionInMs: 0,
132
+ }),
133
+ criteria({
134
+ checkOn: CheckOn.PortDnsLookupTime,
135
+ filterType: FilterType.LessThan,
136
+ value: 1,
137
+ }),
138
+ );
139
+
140
+ expect(result).not.toBeNull();
141
+ });
142
+
143
+ test("uses an evaluate-over-time aggregate instead of the current phase", async () => {
144
+ const overTimeSpy: ReturnType<typeof jest.spyOn> = jest
145
+ .spyOn(EvaluateOverTime, "getValueOverTime")
146
+ .mockResolvedValue(250);
147
+
148
+ const response: ProbeMonitorResponse = buildResponse({
149
+ dnsLookupInMs: 5,
150
+ tcpConnectInMs: 10,
151
+ totalConnectionInMs: 15,
152
+ });
153
+ const result: string | null = await evaluate(
154
+ response,
155
+ criteria({
156
+ checkOn: CheckOn.PortDnsLookupTime,
157
+ value: 200,
158
+ evaluateOverTime: true,
159
+ }),
160
+ );
161
+
162
+ expect(result).not.toBeNull();
163
+ expect(overTimeSpy).toHaveBeenCalledWith(
164
+ expect.objectContaining({
165
+ projectId: response.projectId,
166
+ monitorId: response.monitorId,
167
+ metricType: CheckOn.PortDnsLookupTime,
168
+ }),
169
+ );
170
+ });
171
+
172
+ test("does not replace a zero evaluate-over-time aggregate with the current value", async () => {
173
+ jest.spyOn(EvaluateOverTime, "getValueOverTime").mockResolvedValue(0);
174
+
175
+ const result: string | null = await evaluate(
176
+ buildResponse({
177
+ dnsLookupInMs: 500,
178
+ tcpConnectInMs: 10,
179
+ totalConnectionInMs: 510,
180
+ }),
181
+ criteria({
182
+ checkOn: CheckOn.PortDnsLookupTime,
183
+ filterType: FilterType.LessThan,
184
+ value: 1,
185
+ evaluateOverTime: true,
186
+ }),
187
+ );
188
+
189
+ expect(result).not.toBeNull();
190
+ });
191
+
192
+ test("falls back to the current phase if the history query fails", async () => {
193
+ jest
194
+ .spyOn(EvaluateOverTime, "getValueOverTime")
195
+ .mockRejectedValue(new Error("history unavailable"));
196
+
197
+ const result: string | null = await evaluate(
198
+ buildResponse({
199
+ dnsLookupInMs: 1,
200
+ tcpConnectInMs: 250,
201
+ totalConnectionInMs: 251,
202
+ }),
203
+ criteria({
204
+ checkOn: CheckOn.PortTcpConnectTime,
205
+ value: 200,
206
+ evaluateOverTime: true,
207
+ }),
208
+ );
209
+
210
+ expect(result).not.toBeNull();
211
+ });
212
+ });