@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
@@ -13,8 +13,10 @@ import AIRunService from "../../../../Server/Services/AIRunService";
13
13
  import AIRunEventService from "../../../../Server/Services/AIRunEventService";
14
14
  import AIRun from "../../../../Models/DatabaseModels/AIRun";
15
15
  import AIRunEvent from "../../../../Models/DatabaseModels/AIRunEvent";
16
+ import AIRunEventType from "../../../../Types/AI/AIRunEventType";
16
17
  import AIRunType from "../../../../Types/AI/AIRunType";
17
18
  import AIRunStatus from "../../../../Types/AI/AIRunStatus";
19
+ import AIRunCodeFixRecommendation from "../../../../Types/AI/AIRunCodeFixRecommendation";
18
20
  import ObjectID from "../../../../Types/ObjectID";
19
21
  import PositiveNumber from "../../../../Types/PositiveNumber";
20
22
  import { describe, expect, test, afterEach, beforeEach } from "@jest/globals";
@@ -74,7 +76,11 @@ describe("AIInvestigationQueue.failOrRequeue — the settlement outcome", () =>
74
76
  expect(update).toHaveBeenCalledTimes(1);
75
77
  expect(update).toHaveBeenCalledWith(
76
78
  expect.objectContaining({
77
- set: expect.objectContaining({ status: AIRunStatus.Queued }),
79
+ expectedAttemptCount: 1,
80
+ set: expect.objectContaining({
81
+ status: AIRunStatus.Queued,
82
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
83
+ }),
78
84
  }),
79
85
  );
80
86
  });
@@ -113,7 +119,11 @@ describe("AIInvestigationQueue.failOrRequeue — the settlement outcome", () =>
113
119
  expect(outcome).toBe("finalized");
114
120
  expect(update).toHaveBeenCalledWith(
115
121
  expect.objectContaining({
116
- set: expect.objectContaining({ status: AIRunStatus.Error }),
122
+ expectedAttemptCount: 1,
123
+ set: expect.objectContaining({
124
+ status: AIRunStatus.Error,
125
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
126
+ }),
117
127
  }),
118
128
  );
119
129
  });
@@ -158,7 +168,7 @@ describe("AIInvestigationQueue.requeueOrMarkStale — the terminal-stale hand-of
158
168
  const incidentId: ObjectID = ObjectID.generate();
159
169
  jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
160
170
 
161
- const outcome: "requeued" | "stale" =
171
+ const outcome: "requeued" | "stale" | "noop" =
162
172
  await AIInvestigationQueue.requeueOrMarkStale({
163
173
  id: ObjectID.generate(),
164
174
  attemptCount: MAX_INVESTIGATION_ATTEMPTS,
@@ -168,6 +178,15 @@ describe("AIInvestigationQueue.requeueOrMarkStale — the terminal-stale hand-of
168
178
  });
169
179
 
170
180
  expect(outcome).toBe("stale");
181
+ expect(AIRunService.attemptStatusTransition).toHaveBeenCalledWith(
182
+ expect.objectContaining({
183
+ expectedAttemptCount: MAX_INVESTIGATION_ATTEMPTS,
184
+ set: expect.objectContaining({
185
+ status: AIRunStatus.Stale,
186
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
187
+ }),
188
+ }),
189
+ );
171
190
  expect(handoff).toHaveBeenCalledTimes(1);
172
191
  expect(handoff).toHaveBeenCalledWith(
173
192
  expect.objectContaining({ projectId, incidentId }),
@@ -175,18 +194,34 @@ describe("AIInvestigationQueue.requeueOrMarkStale — the terminal-stale hand-of
175
194
  });
176
195
 
177
196
  test("a requeued stale run is NOT settled — the retry owns it", async () => {
178
- jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
197
+ const transition: jest.SpyInstance = jest
198
+ .spyOn(AIRunService, "attemptStatusTransition")
199
+ .mockResolvedValue(1);
200
+ const staleHeartbeat: Date = new Date("2026-08-07T12:00:00.000Z");
201
+ const runId: ObjectID = ObjectID.generate();
179
202
 
180
- const outcome: "requeued" | "stale" =
203
+ const outcome: "requeued" | "stale" | "noop" =
181
204
  await AIInvestigationQueue.requeueOrMarkStale({
182
- id: ObjectID.generate(),
205
+ id: runId,
183
206
  attemptCount: 1,
207
+ lastHeartbeatAt: staleHeartbeat,
184
208
  runType: AIRunType.Investigation,
185
209
  projectId: ObjectID.generate(),
186
210
  triggeredByIncidentId: ObjectID.generate(),
187
211
  });
188
212
 
189
213
  expect(outcome).toBe("requeued");
214
+ expect(transition).toHaveBeenCalledWith(
215
+ expect.objectContaining({
216
+ aiRunId: runId,
217
+ expectedAttemptCount: 1,
218
+ expectedLastHeartbeatAt: staleHeartbeat,
219
+ set: expect.objectContaining({
220
+ status: AIRunStatus.Queued,
221
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
222
+ }),
223
+ }),
224
+ );
190
225
  expect(handoff).not.toHaveBeenCalled();
191
226
  });
192
227
 
@@ -208,14 +243,16 @@ describe("AIInvestigationQueue.requeueOrMarkStale — the terminal-stale hand-of
208
243
  test("a lost Stale transition does not hand off — the winning actor settles", async () => {
209
244
  jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(0);
210
245
 
211
- await AIInvestigationQueue.requeueOrMarkStale({
212
- id: ObjectID.generate(),
213
- attemptCount: MAX_INVESTIGATION_ATTEMPTS,
214
- runType: AIRunType.Investigation,
215
- projectId: ObjectID.generate(),
216
- triggeredByIncidentId: ObjectID.generate(),
217
- });
246
+ const outcome: "requeued" | "stale" | "noop" =
247
+ await AIInvestigationQueue.requeueOrMarkStale({
248
+ id: ObjectID.generate(),
249
+ attemptCount: MAX_INVESTIGATION_ATTEMPTS,
250
+ runType: AIRunType.Investigation,
251
+ projectId: ObjectID.generate(),
252
+ triggeredByIncidentId: ObjectID.generate(),
253
+ });
218
254
 
255
+ expect(outcome).toBe("noop");
219
256
  expect(handoff).not.toHaveBeenCalled();
220
257
  });
221
258
  });
@@ -268,7 +305,10 @@ describe("AIInvestigationQueue.processQueuedRuns — TTL expiry settles too", ()
268
305
 
269
306
  expect(update).toHaveBeenCalledWith(
270
307
  expect.objectContaining({
271
- set: expect.objectContaining({ status: AIRunStatus.Cancelled }),
308
+ set: expect.objectContaining({
309
+ status: AIRunStatus.Cancelled,
310
+ codeFixRecommendation: AIRunCodeFixRecommendation.NotRecommended,
311
+ }),
272
312
  }),
273
313
  );
274
314
  expect(handoff).not.toHaveBeenCalled();
@@ -296,6 +336,7 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
296
336
  // Records call order so "after postAnalysis" is provable, not assumed.
297
337
  let callOrder: Array<string>;
298
338
  let postAnalysis: jest.Mock;
339
+ let onCodeFixRecommended: jest.Mock;
299
340
  let onSettled: jest.Mock;
300
341
 
301
342
  function makeResult(
@@ -311,22 +352,37 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
311
352
  };
312
353
  }
313
354
 
314
- function makeRequest(): InvestigationRequest {
355
+ function makeRequest(
356
+ overrides: Partial<InvestigationRequest> = {},
357
+ ): InvestigationRequest {
315
358
  return {
316
359
  feature: "Test Investigation",
317
360
  contextSummary: "# Subject",
361
+ persistCodeFixRecommendation: true,
318
362
  postAnalysis:
319
363
  postAnalysis as unknown as InvestigationRequest["postAnalysis"],
364
+ onCodeFixRecommended:
365
+ onCodeFixRecommended as unknown as InvestigationRequest["onCodeFixRecommended"],
320
366
  onSettled: onSettled as unknown as InvestigationRequest["onSettled"],
367
+ ...overrides,
321
368
  };
322
369
  }
323
370
 
324
- function executeRun(): Promise<void> {
371
+ function executeRun(
372
+ request: InvestigationRequest = makeRequest(),
373
+ ): Promise<void> {
325
374
  return AIInvestigationEngine.executeRun({
326
375
  aiRunId,
327
376
  projectId,
328
377
  attemptCount: 1,
329
- request: makeRequest(),
378
+ request,
379
+ });
380
+ }
381
+
382
+ function emittedEventTypes(): Array<AIRunEventType> {
383
+ const create: jest.Mock = AIRunEventService.create as unknown as jest.Mock;
384
+ return create.mock.calls.map((call: Array<unknown>): AIRunEventType => {
385
+ return (call[0] as { data: AIRunEvent }).data.eventType!;
330
386
  });
331
387
  }
332
388
 
@@ -335,6 +391,9 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
335
391
  postAnalysis = jest.fn(async (): Promise<void> => {
336
392
  callOrder.push("postAnalysis");
337
393
  });
394
+ onCodeFixRecommended = jest.fn(async (): Promise<void> => {
395
+ callOrder.push("autoEnqueue");
396
+ });
338
397
  onSettled = jest.fn(async (): Promise<void> => {
339
398
  callOrder.push("onSettled");
340
399
  });
@@ -348,7 +407,14 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
348
407
  .mockResolvedValue({} as unknown as AIRunEvent);
349
408
  jest
350
409
  .spyOn(AIConfidenceSignal, "computeConfidenceSignal")
351
- .mockResolvedValue({ confident: true, source: "classification" });
410
+ .mockResolvedValue({
411
+ confident: true,
412
+ codeFixRecommended: true,
413
+ source: "classification",
414
+ });
415
+ jest
416
+ .spyOn(AIRunService, "finalizeInvestigationCodeFixRecommendation")
417
+ .mockResolvedValue(1);
352
418
  });
353
419
 
354
420
  afterEach(() => {
@@ -356,17 +422,211 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
356
422
  handoff.mockClear();
357
423
  });
358
424
 
359
- test("a successful run settles AFTER the analysis was posted", async () => {
425
+ test("a successful run posts, atomically persists the snapshot, then auto-enqueues and settles", async () => {
426
+ jest
427
+ .spyOn(ObservabilityAssistant, "answerQuestion")
428
+ .mockResolvedValue(makeResult());
429
+ const complete: jest.SpyInstance = jest
430
+ .spyOn(AIRunService, "attemptStatusTransition")
431
+ .mockResolvedValue(1);
432
+ postAnalysis.mockImplementation(async (): Promise<void> => {
433
+ expect(emittedEventTypes()).not.toContain(AIRunEventType.RunCompleted);
434
+ callOrder.push("postAnalysis");
435
+ });
436
+ (
437
+ AIRunService.finalizeInvestigationCodeFixRecommendation as unknown as jest.Mock
438
+ ).mockImplementation(async (): Promise<number> => {
439
+ callOrder.push("persistRecommendation");
440
+ return 1;
441
+ });
442
+ (AIRunEventService.create as unknown as jest.Mock).mockImplementation(
443
+ async (data: { data: AIRunEvent }): Promise<AIRunEvent> => {
444
+ if (data.data.eventType === AIRunEventType.RunCompleted) {
445
+ callOrder.push("runCompleted");
446
+ }
447
+ return {} as AIRunEvent;
448
+ },
449
+ );
450
+
451
+ await executeRun();
452
+
453
+ expect(postAnalysis).toHaveBeenCalledTimes(1);
454
+ expect(onSettled).toHaveBeenCalledTimes(1);
455
+ expect(callOrder).toEqual([
456
+ "postAnalysis",
457
+ "persistRecommendation",
458
+ "autoEnqueue",
459
+ "runCompleted",
460
+ "onSettled",
461
+ ]);
462
+ expect(emittedEventTypes()).toContain(AIRunEventType.RunCompleted);
463
+ expect(complete).toHaveBeenCalledWith(
464
+ expect.objectContaining({
465
+ fromStatus: AIRunStatus.Running,
466
+ expectedAttemptCount: 1,
467
+ set: expect.objectContaining({
468
+ status: AIRunStatus.Completed,
469
+ codeFixRecommendation: AIRunCodeFixRecommendation.Pending,
470
+ }),
471
+ }),
472
+ );
473
+
474
+ const postedAnalysisMarkdown: string = postAnalysis.mock.calls[0]![0]
475
+ .analysisMarkdown as string;
476
+ expect(
477
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
478
+ ).toHaveBeenCalledWith({
479
+ aiRunId,
480
+ recommendation: AIRunCodeFixRecommendation.Recommended,
481
+ taskContext: {
482
+ sourceInvestigationRunId: aiRunId.toString(),
483
+ sourceInvestigationAnalysisMarkdown: postedAnalysisMarkdown,
484
+ },
485
+ });
486
+ expect(onCodeFixRecommended).toHaveBeenCalledWith({
487
+ analysisMarkdown: postedAnalysisMarkdown,
488
+ });
489
+ expect(postedAnalysisMarkdown).toContain(
490
+ "## 🧠 AI — Automated Root Cause Analysis",
491
+ );
492
+ });
493
+
494
+ test("a confident non-code analysis settles NotRecommended", async () => {
360
495
  jest
361
496
  .spyOn(ObservabilityAssistant, "answerQuestion")
362
497
  .mockResolvedValue(makeResult());
363
498
  jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
499
+ jest
500
+ .spyOn(AIConfidenceSignal, "computeConfidenceSignal")
501
+ .mockResolvedValue({
502
+ confident: true,
503
+ codeFixRecommended: false,
504
+ source: "classification",
505
+ });
364
506
 
365
507
  await executeRun();
366
508
 
367
509
  expect(postAnalysis).toHaveBeenCalledTimes(1);
510
+ expect(
511
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
512
+ ).toHaveBeenCalledWith({
513
+ aiRunId,
514
+ recommendation: AIRunCodeFixRecommendation.NotRecommended,
515
+ });
516
+ expect(onCodeFixRecommended).not.toHaveBeenCalled();
517
+ });
518
+
519
+ test("an inconsistent positive field fails closed through the shared code-fix helper", async () => {
520
+ jest
521
+ .spyOn(ObservabilityAssistant, "answerQuestion")
522
+ .mockResolvedValue(makeResult());
523
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
524
+ jest
525
+ .spyOn(AIConfidenceSignal, "computeConfidenceSignal")
526
+ .mockResolvedValue({
527
+ confident: false,
528
+ codeFixRecommended: true,
529
+ source: "classification",
530
+ });
531
+
532
+ await executeRun();
533
+
534
+ expect(
535
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
536
+ ).toHaveBeenCalledWith({
537
+ aiRunId,
538
+ recommendation: AIRunCodeFixRecommendation.NotRecommended,
539
+ });
540
+ expect(onCodeFixRecommended).not.toHaveBeenCalled();
541
+ });
542
+
543
+ test("a transient recommendation write is retried up to a successful third attempt", async () => {
544
+ jest
545
+ .spyOn(ObservabilityAssistant, "answerQuestion")
546
+ .mockResolvedValue(makeResult());
547
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
548
+ (
549
+ AIRunService.finalizeInvestigationCodeFixRecommendation as unknown as jest.Mock
550
+ )
551
+ .mockRejectedValueOnce(new Error("database unavailable"))
552
+ .mockRejectedValueOnce(new Error("connection reset"))
553
+ .mockResolvedValueOnce(1);
554
+
555
+ await executeRun();
556
+
557
+ expect(
558
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
559
+ ).toHaveBeenCalledTimes(3);
560
+ expect(onCodeFixRecommended).toHaveBeenCalledTimes(1);
368
561
  expect(onSettled).toHaveBeenCalledTimes(1);
369
- expect(callOrder).toEqual(["postAnalysis", "onSettled"]);
562
+ });
563
+
564
+ test("a zero-row recommendation write is safe and is not retried", async () => {
565
+ jest
566
+ .spyOn(ObservabilityAssistant, "answerQuestion")
567
+ .mockResolvedValue(makeResult());
568
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
569
+ (
570
+ AIRunService.finalizeInvestigationCodeFixRecommendation as unknown as jest.Mock
571
+ ).mockResolvedValue(0);
572
+
573
+ await executeRun();
574
+
575
+ expect(
576
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
577
+ ).toHaveBeenCalledTimes(1);
578
+ expect(onCodeFixRecommended).not.toHaveBeenCalled();
579
+ expect(onSettled).toHaveBeenCalledTimes(1);
580
+ });
581
+
582
+ test("a non-incident engine consumer neither enters Pending nor persists a recommendation", async () => {
583
+ jest
584
+ .spyOn(ObservabilityAssistant, "answerQuestion")
585
+ .mockResolvedValue(makeResult());
586
+ const complete: jest.SpyInstance = jest
587
+ .spyOn(AIRunService, "attemptStatusTransition")
588
+ .mockResolvedValue(1);
589
+
590
+ await executeRun(makeRequest({ persistCodeFixRecommendation: undefined }));
591
+
592
+ const completedSet: Record<string, unknown> = complete.mock.calls[0]![0]
593
+ .set as Record<string, unknown>;
594
+ expect(completedSet["codeFixRecommendation"]).toBeUndefined();
595
+ expect(
596
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
597
+ ).not.toHaveBeenCalled();
598
+ expect(postAnalysis).toHaveBeenCalledTimes(1);
599
+ });
600
+
601
+ test("carries the subject lane through the assistant and confidence calls", async () => {
602
+ const incidentId: ObjectID = ObjectID.generate();
603
+ const answer: jest.SpyInstance = jest
604
+ .spyOn(ObservabilityAssistant, "answerQuestion")
605
+ .mockResolvedValue(makeResult());
606
+ const confidence: jest.SpyInstance = jest.spyOn(
607
+ AIConfidenceSignal,
608
+ "computeConfidenceSignal",
609
+ );
610
+ jest.spyOn(AIRunService, "attemptStatusTransition").mockResolvedValue(1);
611
+
612
+ await executeRun(makeRequest({ incidentId }));
613
+
614
+ expect(answer).toHaveBeenCalledWith(
615
+ expect.objectContaining({
616
+ projectId,
617
+ aiRunId,
618
+ incidentId,
619
+ alertId: undefined,
620
+ }),
621
+ );
622
+ expect(confidence).toHaveBeenCalledWith(
623
+ expect.objectContaining({
624
+ projectId,
625
+ aiRunId,
626
+ incidentId,
627
+ alertId: undefined,
628
+ }),
629
+ );
370
630
  });
371
631
 
372
632
  test("an empty analysis still settles — but posts nothing", async () => {
@@ -384,6 +644,13 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
384
644
  expect(postAnalysis).not.toHaveBeenCalled();
385
645
  expect(confidence).not.toHaveBeenCalled();
386
646
  expect(onSettled).toHaveBeenCalledTimes(1);
647
+ expect(emittedEventTypes()).toContain(AIRunEventType.RunCompleted);
648
+ expect(
649
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
650
+ ).toHaveBeenCalledWith({
651
+ aiRunId,
652
+ recommendation: AIRunCodeFixRecommendation.NotRecommended,
653
+ });
387
654
  });
388
655
 
389
656
  test("a lost Completed CAS neither posts nor settles — the winning attempt owns both", async () => {
@@ -396,6 +663,9 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
396
663
 
397
664
  expect(postAnalysis).not.toHaveBeenCalled();
398
665
  expect(onSettled).not.toHaveBeenCalled();
666
+ expect(
667
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
668
+ ).not.toHaveBeenCalled();
399
669
  });
400
670
 
401
671
  test("an agent failure that failOrRequeue FINALIZED settles", async () => {
@@ -410,6 +680,7 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
410
680
 
411
681
  expect(postAnalysis).not.toHaveBeenCalled();
412
682
  expect(onSettled).toHaveBeenCalledTimes(1);
683
+ expect(emittedEventTypes()).toContain(AIRunEventType.RunFailed);
413
684
  });
414
685
 
415
686
  test("an agent failure that was REQUEUED does not settle — the retry will", async () => {
@@ -423,6 +694,19 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
423
694
  await executeRun();
424
695
 
425
696
  expect(onSettled).not.toHaveBeenCalled();
697
+ expect(emittedEventTypes()).not.toContain(AIRunEventType.RunFailed);
698
+ });
699
+
700
+ test("a stale failing attempt that lost ownership emits no terminal event", async () => {
701
+ jest
702
+ .spyOn(ObservabilityAssistant, "answerQuestion")
703
+ .mockRejectedValue(new Error("stale attempt finished late"));
704
+ jest.spyOn(AIInvestigationQueue, "failOrRequeue").mockResolvedValue("noop");
705
+
706
+ await executeRun();
707
+
708
+ expect(onSettled).not.toHaveBeenCalled();
709
+ expect(emittedEventTypes()).not.toContain(AIRunEventType.RunFailed);
426
710
  });
427
711
 
428
712
  test("a postAnalysis failure after the WON Completed transition still settles", async () => {
@@ -439,6 +723,15 @@ describe("AIInvestigationEngine.executeRun — the onSettled contract", () => {
439
723
  await executeRun();
440
724
 
441
725
  expect(onSettled).toHaveBeenCalledTimes(1);
726
+ expect(emittedEventTypes()).not.toContain(AIRunEventType.RunCompleted);
727
+ expect(emittedEventTypes()).toContain(AIRunEventType.RunFailed);
728
+ expect(
729
+ AIRunService.finalizeInvestigationCodeFixRecommendation,
730
+ ).toHaveBeenCalledWith({
731
+ aiRunId,
732
+ recommendation: AIRunCodeFixRecommendation.NotRecommended,
733
+ });
734
+ expect(onCodeFixRecommended).not.toHaveBeenCalled();
442
735
  });
443
736
 
444
737
  test("an onSettled failure never rejects executeRun", async () => {