@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
@@ -1183,6 +1183,7 @@ export default class StatusPage extends BaseModel {
1183
1183
  description:
1184
1184
  "Password required to unlock a private status page. This value is stored as a secure hash.",
1185
1185
  hashed: true,
1186
+ hashSaltColumn: "masterPasswordSalt",
1186
1187
  type: TableColumnType.HashedString,
1187
1188
  placeholder: "Enter a new master password",
1188
1189
  })
@@ -1194,6 +1195,33 @@ export default class StatusPage extends BaseModel {
1194
1195
  })
1195
1196
  public masterPassword?: HashedString = undefined;
1196
1197
 
1198
+ /*
1199
+ * Per-status-page salt mixed into `masterPassword`. Written by the database
1200
+ * write path on every master-password write and never exposed to API
1201
+ * callers. Nullable so existing unsalted hashes can be verified and
1202
+ * upgraded after a successful unlock.
1203
+ */
1204
+ @ColumnAccessControl({
1205
+ create: [],
1206
+ read: [],
1207
+ update: [],
1208
+ })
1209
+ @TableColumn({
1210
+ title: "Master Password Salt",
1211
+ description:
1212
+ "Per-status-page random salt mixed into this status page's master password hash.",
1213
+ computed: true,
1214
+ type: TableColumnType.ShortText,
1215
+ hideColumnInDocumentation: true,
1216
+ })
1217
+ @Column({
1218
+ type: ColumnType.ShortText,
1219
+ length: ColumnLength.ShortText,
1220
+ unique: false,
1221
+ nullable: true,
1222
+ })
1223
+ public masterPasswordSalt?: string = undefined;
1224
+
1197
1225
  @ColumnAccessControl({
1198
1226
  create: [
1199
1227
  Permission.ProjectOwner,
@@ -713,6 +713,7 @@ export default class StatusPageAnnouncement extends BaseModel {
713
713
  ],
714
714
  })
715
715
  @TableColumn({
716
+ computed: true,
716
717
  type: TableColumnType.VeryLongText,
717
718
  title: "Notification Status Message",
718
719
  description:
@@ -7,8 +7,7 @@ import AIRunService from "../Services/AIRunService";
7
7
  import AIRunEventService from "../Services/AIRunEventService";
8
8
  import IncidentService from "../Services/IncidentService";
9
9
  import AlertService from "../Services/AlertService";
10
- import IncidentFeedService from "../Services/IncidentFeedService";
11
- import AlertFeedService from "../Services/AlertFeedService";
10
+ import PostedRootCause from "../Utils/AI/SRE/PostedRootCause";
12
11
  import Express, {
13
12
  ExpressRequest,
14
13
  ExpressResponse,
@@ -27,12 +26,6 @@ import AIAgentTaskPullRequest from "../../Models/DatabaseModels/AIAgentTaskPullR
27
26
  import AIRun from "../../Models/DatabaseModels/AIRun";
28
27
  import Incident from "../../Models/DatabaseModels/Incident";
29
28
  import Alert from "../../Models/DatabaseModels/Alert";
30
- import IncidentFeed, {
31
- IncidentFeedEventType,
32
- } from "../../Models/DatabaseModels/IncidentFeed";
33
- import AlertFeed, {
34
- AlertFeedEventType,
35
- } from "../../Models/DatabaseModels/AlertFeed";
36
29
  import AIRunEventType from "../../Types/AI/AIRunEventType";
37
30
  import AIRunType from "../../Types/AI/AIRunType";
38
31
  import FixVerificationStatus from "../../Types/AI/FixVerificationStatus";
@@ -41,7 +34,9 @@ import CodeFixTaskType, {
41
34
  CodeFixTaskTypeHelper,
42
35
  } from "../../Types/AI/CodeFixTaskType";
43
36
  import CodeFixTaskContext, {
37
+ getInvestigationCodeFixTaskSnapshot,
44
38
  ImplicatedSpan,
39
+ InvestigationCodeFixTaskSnapshot,
45
40
  PerformanceCodeLocation,
46
41
  PerformanceFinding,
47
42
  } from "../../Types/AI/CodeFixTaskContext";
@@ -62,7 +57,6 @@ import {
62
57
  LLMToolCall,
63
58
  LLMToolDefinition,
64
59
  } from "../Utils/LLM/LLMService";
65
- import SortOrder from "../../Types/BaseDatabase/SortOrder";
66
60
  import BadDataException from "../../Types/Exception/BadDataException";
67
61
  import { JSONObject } from "../../Types/JSON";
68
62
  import ObjectID from "../../Types/ObjectID";
@@ -496,14 +490,12 @@ export default class AIAgentDataAPI {
496
490
  * The route name predates the newer recipes and is kept for agent
497
491
  * compatibility. Two context kinds are served:
498
492
  *
499
- * - Incident/alert-subject recipes (ImproveInstrumentation,
500
- * FixFromIncident): the investigation's posted analysis + subject
501
- * metadata + the repository resolved without a stack trace. The
502
- * analysis text comes from the subject's latest RootCause feed item:
503
- * the AI's postAnalysis is the only writer of RootCause feed
504
- * events, it writes them for BOTH subjects and BOTH confidence
505
- * outcomes (quiet mode only mutes the workspace ping), so the feed
506
- * item IS the investigation run's persisted output.
493
+ * - Incident/alert-subject recipes: subject metadata + the repository
494
+ * resolved without a stack trace. ImproveInstrumentation reads the
495
+ * subject's latest RootCause feed item. FixFromIncident instead reads
496
+ * the immutable investigation snapshot captured in AIRun.taskContext;
497
+ * a later re-investigation must never replace the Recommended analysis
498
+ * that authorized a code-fix task.
507
499
  *
508
500
  * - Trace-evidence recipes (FixPerformance): the deterministic
509
501
  * span-tree findings stored on AIRun.taskContext at trigger time
@@ -581,6 +573,10 @@ export default class AIAgentDataAPI {
581
573
  CodeFixTaskTypeHelper.fromDatabaseValue(run.codeFixTaskType);
582
574
  const contextKind: CodeFixContextKind =
583
575
  CodeFixTaskTypeHelper.getContextKind(taskType);
576
+ const investigationSnapshot: InvestigationCodeFixTaskSnapshot | null =
577
+ taskType === CodeFixTaskType.FixFromIncident
578
+ ? getInvestigationCodeFixTaskSnapshot(run.taskContext)
579
+ : null;
584
580
 
585
581
  if (
586
582
  run.runType !== AIRunType.CodeFix ||
@@ -595,6 +591,25 @@ export default class AIAgentDataAPI {
595
591
  );
596
592
  }
597
593
 
594
+ /*
595
+ * FixFromIncident authorization covered one exact Recommended
596
+ * investigation. Never substitute the subject's current RootCause:
597
+ * a re-investigation may have posted a different, non-code analysis
598
+ * while this task waited in the queue.
599
+ */
600
+ if (
601
+ taskType === CodeFixTaskType.FixFromIncident &&
602
+ !investigationSnapshot
603
+ ) {
604
+ return Response.sendErrorResponse(
605
+ req,
606
+ res,
607
+ new BadDataException(
608
+ "This fix-from-incident task has no complete pinned investigation analysis snapshot — it cannot be executed safely.",
609
+ ),
610
+ );
611
+ }
612
+
598
613
  /*
599
614
  * Service-scoped instrumentation recipes (ImproveLogging /
600
615
  * ImproveTracing): the context is just the service — resolve the
@@ -864,7 +879,8 @@ export default class AIAgentDataAPI {
864
879
  * fine when the subject has no monitor.
865
880
  */
866
881
  let serviceName: string | null = null;
867
- let analysisMarkdown: string | null = null;
882
+ let analysisMarkdown: string | null =
883
+ investigationSnapshot?.investigationAnalysisMarkdown || null;
868
884
 
869
885
  if (run.triggeredByIncidentId) {
870
886
  const incident: Incident | null = await IncidentService.findOneById(
@@ -900,24 +916,11 @@ export default class AIAgentDataAPI {
900
916
  })
901
917
  .filter(Boolean)[0] || null;
902
918
 
903
- const feedItem: IncidentFeed | null =
904
- await IncidentFeedService.findOneBy({
905
- query: {
906
- incidentId: run.triggeredByIncidentId,
907
- incidentFeedEventType: IncidentFeedEventType.RootCause,
908
- },
909
- select: {
910
- feedInfoInMarkdown: true,
911
- },
912
- sort: {
913
- createdAt: SortOrder.Descending,
914
- },
915
- props: {
916
- isRoot: true,
917
- },
918
- });
919
-
920
- analysisMarkdown = feedItem?.feedInfoInMarkdown || null;
919
+ if (taskType !== CodeFixTaskType.FixFromIncident) {
920
+ analysisMarkdown = await PostedRootCause.getForIncident(
921
+ run.triggeredByIncidentId,
922
+ );
923
+ }
921
924
  } else {
922
925
  const alert: Alert | null = await AlertService.findOneById({
923
926
  id: run.triggeredByAlertId!,
@@ -945,25 +948,11 @@ export default class AIAgentDataAPI {
945
948
  subjectTitle = alert.title || "Untitled alert";
946
949
  serviceName = alert.monitor?.name || null;
947
950
 
948
- const feedItem: AlertFeed | null = await AlertFeedService.findOneBy(
949
- {
950
- query: {
951
- alertId: run.triggeredByAlertId!,
952
- alertFeedEventType: AlertFeedEventType.RootCause,
953
- },
954
- select: {
955
- feedInfoInMarkdown: true,
956
- },
957
- sort: {
958
- createdAt: SortOrder.Descending,
959
- },
960
- props: {
961
- isRoot: true,
962
- },
963
- },
964
- );
965
-
966
- analysisMarkdown = feedItem?.feedInfoInMarkdown || null;
951
+ if (taskType !== CodeFixTaskType.FixFromIncident) {
952
+ analysisMarkdown = await PostedRootCause.getForAlert(
953
+ run.triggeredByAlertId!,
954
+ );
955
+ }
967
956
  }
968
957
 
969
958
  if (!analysisMarkdown) {
@@ -16,6 +16,8 @@ import Query from "../../Types/BaseDatabase/Query";
16
16
  import { JSONArray, JSONObject } from "../../Types/JSON";
17
17
  import AIRunType from "../../Types/AI/AIRunType";
18
18
  import AIRunHumanVerdict from "../../Types/AI/AIRunHumanVerdict";
19
+ import AIRunStatus from "../../Types/AI/AIRunStatus";
20
+ import AIRunEventType from "../../Types/AI/AIRunEventType";
19
21
  import AIRun from "../../Models/DatabaseModels/AIRun";
20
22
  import AIRunEvent from "../../Models/DatabaseModels/AIRunEvent";
21
23
  import Incident from "../../Models/DatabaseModels/Incident";
@@ -32,6 +34,7 @@ import SpanService from "../Services/SpanService";
32
34
  import FixFromIncidentTaskTrigger from "../Utils/AI/SRE/FixFromIncidentTaskTrigger";
33
35
  import FixPerformanceTaskTrigger from "../Utils/AI/SRE/FixPerformanceTaskTrigger";
34
36
  import TelemetryImprovementTaskTrigger from "../Utils/AI/SRE/TelemetryImprovementTaskTrigger";
37
+ import PostedRootCause from "../Utils/AI/SRE/PostedRootCause";
35
38
  import CodeFixTaskType from "../../Types/AI/CodeFixTaskType";
36
39
  import { AnalyzableSpan } from "../Utils/AI/PerfEvidence/SpanTreeAnalyzer";
37
40
 
@@ -47,6 +50,100 @@ const MAX_ANALYZED_TRACE_SPANS: number = 500;
47
50
 
48
51
  const MAX_EVENTS: number = 500;
49
52
 
53
+ /*
54
+ * `aiRunId` is the established dashboard API field. The investigation panel
55
+ * introduced the more explicit `investigationRunId` name while this feature
56
+ * was in flight, so accept either spelling without ever allowing two
57
+ * different ids in one request. Both names identify the exact displayed run.
58
+ */
59
+ function getDisplayedInvestigationRunId(req: ExpressRequest): ObjectID {
60
+ const aiRunId: string =
61
+ typeof req.body["aiRunId"] === "string"
62
+ ? (req.body["aiRunId"] as string).trim()
63
+ : "";
64
+ const investigationRunId: string =
65
+ typeof req.body["investigationRunId"] === "string"
66
+ ? (req.body["investigationRunId"] as string).trim()
67
+ : "";
68
+
69
+ if (!aiRunId && !investigationRunId) {
70
+ throw new BadDataException("investigationRunId (or aiRunId) is required.");
71
+ }
72
+
73
+ if (aiRunId && investigationRunId && aiRunId !== investigationRunId) {
74
+ throw new BadDataException(
75
+ "aiRunId and investigationRunId must identify the same displayed investigation.",
76
+ );
77
+ }
78
+
79
+ const selectedRunId: string = investigationRunId || aiRunId;
80
+ ObjectID.validateUUID(selectedRunId);
81
+ return new ObjectID(selectedRunId);
82
+ }
83
+
84
+ /*
85
+ * The run wins its Running -> Completed transition before it performs the
86
+ * confidence check and posts the RootCause feed item. A final RunCompleted or
87
+ * RunFailed event is emitted when that finalization settles; failures from
88
+ * retried attempts precede a later RunStarted. This upper bound is a crash
89
+ * failsafe and deliberately leaves ample margin above the bounded confidence
90
+ * classification deadline plus feed publication.
91
+ */
92
+ export const ANALYSIS_FINALIZATION_TIMEOUT_MS: number = 10 * 60 * 1000;
93
+ // Database/application clocks can differ briefly around the Completed write.
94
+ export const ANALYSIS_COMPLETION_CLOCK_SKEW_MS: number = 60 * 1000;
95
+
96
+ export function isAnalysisPendingForRun(data: {
97
+ run: AIRun;
98
+ events: Array<AIRunEvent>;
99
+ analysisMarkdown: string | null;
100
+ currentDate?: Date | undefined;
101
+ }): boolean {
102
+ if (
103
+ data.run.status !== AIRunStatus.Completed ||
104
+ data.analysisMarkdown ||
105
+ !data.run.completedAt
106
+ ) {
107
+ return false;
108
+ }
109
+
110
+ /*
111
+ * A retried run retains RunFailed from earlier attempts. Only a settlement
112
+ * event emitted after the latest RunStarted belongs to the attempt that won
113
+ * the Completed transition; an older failure must not stop report polling.
114
+ * sendLatestInvestigation supplies events in sequence order.
115
+ */
116
+ let latestRunStartedIndex: number = -1;
117
+ data.events.forEach((event: AIRunEvent, index: number): void => {
118
+ if (event.eventType === AIRunEventType.RunStarted) {
119
+ latestRunStartedIndex = index;
120
+ }
121
+ });
122
+
123
+ const hasFinalizationEvent: boolean = data.events.some(
124
+ (event: AIRunEvent, index: number): boolean => {
125
+ return (
126
+ index > latestRunStartedIndex &&
127
+ (event.eventType === AIRunEventType.RunCompleted ||
128
+ event.eventType === AIRunEventType.RunFailed)
129
+ );
130
+ },
131
+ );
132
+
133
+ if (hasFinalizationEvent) {
134
+ return false;
135
+ }
136
+
137
+ const currentDate: Date = data.currentDate || new Date();
138
+ const millisecondsSinceCompletion: number =
139
+ currentDate.getTime() - data.run.completedAt.getTime();
140
+
141
+ return (
142
+ millisecondsSinceCompletion >= -ANALYSIS_COMPLETION_CLOCK_SKEW_MS &&
143
+ millisecondsSinceCompletion < ANALYSIS_FINALIZATION_TIMEOUT_MS
144
+ );
145
+ }
146
+
50
147
  /*
51
148
  * Returns the latest AI investigation (the AIRun + its ordered
52
149
  * AIRunEvents) for an incident or alert, so the dashboard can render a live
@@ -80,6 +177,10 @@ async function sendLatestInvestigation(
80
177
  req: ExpressRequest,
81
178
  res: ExpressResponse,
82
179
  runQuery: Query<AIRun>,
180
+ subject: {
181
+ incidentId?: ObjectID | undefined;
182
+ alertId?: ObjectID | undefined;
183
+ },
83
184
  ): Promise<void> {
84
185
  const runs: Array<AIRun> = await AIRunService.findBy({
85
186
  query: runQuery,
@@ -93,6 +194,7 @@ async function sendLatestInvestigation(
93
194
  toolCallCount: true,
94
195
  totalTokens: true,
95
196
  createdAt: true,
197
+ codeFixRecommendation: true,
96
198
  // Measurement layer: the panel renders verdict/grade state from these.
97
199
  humanVerdict: true,
98
200
  humanVerdictAt: true,
@@ -111,6 +213,8 @@ async function sendLatestInvestigation(
111
213
  Response.sendJsonObjectResponse(req, res, {
112
214
  run: null,
113
215
  events: [],
216
+ analysisMarkdown: null,
217
+ isAnalysisPending: false,
114
218
  });
115
219
  return;
116
220
  }
@@ -138,9 +242,32 @@ async function sendLatestInvestigation(
138
242
 
139
243
  const eventsJson: JSONArray = BaseModel.toJSONArray(events, AIRunEvent);
140
244
 
245
+ /*
246
+ * RootCause is the canonical persisted investigation result. The explicit
247
+ * aiRunId association is immune to application/database clock skew and to
248
+ * overlapping investigations posting out of order.
249
+ */
250
+ let analysisMarkdown: string | null = null;
251
+
252
+ if (run.status === AIRunStatus.Completed && run.completedAt) {
253
+ analysisMarkdown = await PostedRootCause.getForInvestigation({
254
+ ...subject,
255
+ aiRunId: run.id!,
256
+ runCompletedAt: run.completedAt,
257
+ });
258
+ }
259
+
260
+ const isAnalysisPending: boolean = isAnalysisPendingForRun({
261
+ run,
262
+ events,
263
+ analysisMarkdown,
264
+ });
265
+
141
266
  Response.sendJsonObjectResponse(req, res, {
142
267
  run: runJson || null,
143
268
  events: eventsJson,
269
+ analysisMarkdown,
270
+ isAnalysisPending,
144
271
  });
145
272
  }
146
273
 
@@ -178,10 +305,17 @@ router.post(
178
305
  );
179
306
  }
180
307
 
181
- await sendLatestInvestigation(req, res, {
182
- triggeredByIncidentId: incidentId,
183
- runType: AIRunType.Investigation,
184
- });
308
+ await sendLatestInvestigation(
309
+ req,
310
+ res,
311
+ {
312
+ triggeredByIncidentId: incidentId,
313
+ runType: AIRunType.Investigation,
314
+ },
315
+ {
316
+ incidentId,
317
+ },
318
+ );
185
319
  return;
186
320
  } catch (err) {
187
321
  next(err);
@@ -224,10 +358,17 @@ router.post(
224
358
  );
225
359
  }
226
360
 
227
- await sendLatestInvestigation(req, res, {
228
- triggeredByAlertId: alertId,
229
- runType: AIRunType.Investigation,
230
- });
361
+ await sendLatestInvestigation(
362
+ req,
363
+ res,
364
+ {
365
+ triggeredByAlertId: alertId,
366
+ runType: AIRunType.Investigation,
367
+ },
368
+ {
369
+ alertId,
370
+ },
371
+ );
231
372
  return;
232
373
  } catch (err) {
233
374
  next(err);
@@ -238,14 +379,16 @@ router.post(
238
379
 
239
380
  /*
240
381
  * Human verdict capture (Phase 2 measurement layer): one-click Confirm /
241
- * Reject on the investigation panel. Applies to the LATEST COMPLETED
242
- * investigation run for the subject; overwriting is allowed (a user may
382
+ * Reject on the investigation panel. Applies to the exact COMPLETED
383
+ * investigation run displayed to the user; overwriting is allowed (a user may
243
384
  * change their mind), and the request is rejected when no completed
244
385
  * investigation exists. The subject is access-checked under the USER's
245
386
  * permissions first (same idiom as the read routes above); the run itself is
246
387
  * written as root because investigation runs are system-authored.
247
388
  * Body: { subjectType: "incident" | "alert", subjectId,
248
- * verdict: "Confirmed" | "Rejected" }. Response: { runId, verdict }.
389
+ * aiRunId (or its investigationRunId alias), verdict: "Confirmed" |
390
+ * "Rejected" }. The run id binds the mutation to the analysis currently
391
+ * displayed. Response: { runId, verdict }.
249
392
  */
250
393
  router.post(
251
394
  "/ai-investigation/verdict",
@@ -278,6 +421,8 @@ router.post(
278
421
 
279
422
  const subjectId: ObjectID = new ObjectID(subjectIdString);
280
423
 
424
+ const investigationRunId: ObjectID = getDisplayedInvestigationRunId(req);
425
+
281
426
  const verdict: string | undefined = req.body["verdict"] as
282
427
  | string
283
428
  | undefined;
@@ -292,34 +437,42 @@ router.post(
292
437
  }
293
438
 
294
439
  // Access check under the USER's permissions (null when not allowed).
440
+ let projectId: ObjectID | undefined = undefined;
441
+
295
442
  if (subjectType === "incident") {
296
443
  const incident: Incident | null = await IncidentService.findOneById({
297
444
  id: subjectId,
298
- select: { _id: true },
445
+ select: { _id: true, projectId: true },
299
446
  props,
300
447
  });
301
448
 
302
- if (!incident) {
449
+ if (!incident || !incident.projectId) {
303
450
  throw new BadDataException(
304
451
  "Incident not found (or you do not have access to it).",
305
452
  );
306
453
  }
454
+
455
+ projectId = incident.projectId;
307
456
  } else {
308
457
  const alert: Alert | null = await AlertService.findOneById({
309
458
  id: subjectId,
310
- select: { _id: true },
459
+ select: { _id: true, projectId: true },
311
460
  props,
312
461
  });
313
462
 
314
- if (!alert) {
463
+ if (!alert || !alert.projectId) {
315
464
  throw new BadDataException(
316
465
  "Alert not found (or you do not have access to it).",
317
466
  );
318
467
  }
468
+
469
+ projectId = alert.projectId;
319
470
  }
320
471
 
321
472
  const result: { runId: ObjectID; verdict: AIRunHumanVerdict } =
322
- await AIRunService.applyHumanVerdictToLatestInvestigation({
473
+ await AIRunService.applyHumanVerdictToInvestigation({
474
+ aiRunId: investigationRunId,
475
+ projectId,
323
476
  ...(subjectType === "incident"
324
477
  ? { incidentId: subjectId }
325
478
  : { alertId: subjectId }),
@@ -346,7 +499,9 @@ router.post(
346
499
  * access-checked under the USER's permissions first (same idiom as the read
347
500
  * routes above); the trigger's gates (completed investigation, GitHub-App
348
501
  * repository, per-subject dedupe) fail early with a clear message.
349
- * Body: { subjectType: "incident" | "alert", subjectId }. Response:
502
+ * Body: { subjectType: "incident" | "alert", subjectId,
503
+ * aiRunId (or its investigationRunId alias) }. The run id rejects stale
504
+ * clicks instead of silently switching to a newer analysis. Response:
350
505
  * { aiRunId } — the Queued CodeFix run the agent worker will claim.
351
506
  */
352
507
  router.post(
@@ -380,6 +535,8 @@ router.post(
380
535
 
381
536
  const subjectId: ObjectID = new ObjectID(subjectIdString);
382
537
 
538
+ const investigationRunId: ObjectID = getDisplayedInvestigationRunId(req);
539
+
383
540
  // Access check under the USER's permissions (null when not allowed).
384
541
  let projectId: ObjectID | undefined = undefined;
385
542
 
@@ -419,6 +576,7 @@ router.post(
419
576
  ...(subjectType === "incident"
420
577
  ? { incidentId: subjectId }
421
578
  : { alertId: subjectId }),
579
+ investigationRunId,
422
580
  userId: props.userId!,
423
581
  });
424
582
 
@@ -15,11 +15,9 @@ import Response from "../Utils/Response";
15
15
  import BaseAPI from "./BaseAPI";
16
16
  import BadDataException from "../../Types/Exception/BadDataException";
17
17
  import NotFoundException from "../../Types/Exception/NotFoundException";
18
- import HashedString from "../../Types/HashedString";
19
18
  import ObjectID from "../../Types/ObjectID";
20
19
  import Dashboard from "../../Models/DatabaseModels/Dashboard";
21
20
  import DashboardDomain from "../../Models/DatabaseModels/DashboardDomain";
22
- import { EncryptionSecret } from "../EnvironmentConfig";
23
21
  import { DASHBOARD_MASTER_PASSWORD_INVALID_MESSAGE } from "../../Types/Dashboard/MasterPassword";
24
22
  import NotAuthenticatedException from "../../Types/Exception/NotAuthenticatedException";
25
23
  import ForbiddenException from "../../Types/Exception/ForbiddenException";
@@ -1541,10 +1539,9 @@ export default class DashboardAPI extends BaseAPI<
1541
1539
  req.params["dashboardId"] as string,
1542
1540
  );
1543
1541
 
1544
- const password: string | undefined =
1545
- req.body && (req.body["password"] as string);
1542
+ const password: unknown = req.body && req.body["password"];
1546
1543
 
1547
- if (!password) {
1544
+ if (typeof password !== "string" || !password) {
1548
1545
  throw new BadDataException("Master password is required.");
1549
1546
  }
1550
1547
 
@@ -1556,6 +1553,7 @@ export default class DashboardAPI extends BaseAPI<
1556
1553
  projectId: true,
1557
1554
  enableMasterPassword: true,
1558
1555
  masterPassword: true,
1556
+ masterPasswordSalt: true,
1559
1557
  isPublicDashboard: true,
1560
1558
  },
1561
1559
  props: {
@@ -1579,12 +1577,14 @@ export default class DashboardAPI extends BaseAPI<
1579
1577
  );
1580
1578
  }
1581
1579
 
1582
- const hashedInput: string = await HashedString.hashValue(
1583
- password,
1584
- EncryptionSecret,
1585
- );
1580
+ const isMasterPasswordValid: boolean =
1581
+ await DashboardService.verifyHashedColumnValue({
1582
+ item: dashboard,
1583
+ columnName: "masterPassword",
1584
+ plainValue: password,
1585
+ });
1586
1586
 
1587
- if (hashedInput !== dashboard.masterPassword.toString()) {
1587
+ if (!isMasterPasswordValid) {
1588
1588
  throw new BadDataException(
1589
1589
  DASHBOARD_MASTER_PASSWORD_INVALID_MESSAGE,
1590
1590
  );