sparkforensics-server 0.6.0 → 0.8.1

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 (410) hide show
  1. package/index.js +16 -7
  2. package/package.json +1 -1
  3. package/public/assets/AutoscalingChurn-DenWKTv-.js +1 -0
  4. package/public/assets/CacheUtilization-DLz7NdjV.js +1 -0
  5. package/public/assets/CachingOpportunity-zpQIqhzm.js +1 -0
  6. package/public/assets/ChartTheme-DAiARbLP.js +8 -0
  7. package/public/assets/ColdStart-C-9HjxWl.js +1 -0
  8. package/public/assets/ConfigAudit-D0V9tcrJ.js +1 -0
  9. package/public/assets/CoreUsageArea-yeerrljd.js +1 -0
  10. package/public/assets/Dashboard-DkUPrHKV.js +1 -0
  11. package/public/assets/DisclosureContext-DK1_iz6J.js +1 -0
  12. package/public/assets/DuplicatePlanSubtree-xDNDbCd3.js +1 -0
  13. package/public/assets/DurationHistogram-B6jsE0Ov.js +1 -0
  14. package/public/assets/EmptyState-C1uL40VU.js +1 -0
  15. package/public/assets/ExecutorUtilization-DXDZKmSc.js +1 -0
  16. package/public/assets/GcPressure-MRf7I4IG.js +1 -0
  17. package/public/assets/ImpactEstimate-Dm3xWbzV.js +1 -0
  18. package/public/assets/IncompleteRun-CaLOhMtf.js +1 -0
  19. package/public/assets/JobFailures-CzmzlvhO.js +1 -0
  20. package/public/assets/MemoryUtilization-AWUMUjCH.js +1 -0
  21. package/public/assets/NestedLoopJoin-C9sNr6Ss.js +1 -0
  22. package/public/assets/OverBroadcast-BOmRE6ca.js +1 -0
  23. package/public/assets/PartitionHint-BL2EmJfE.js +1 -0
  24. package/public/assets/PartitionSizing-BzBySvUq.js +1 -0
  25. package/public/assets/PlanExplorer-DdiQRcJU.js +1 -0
  26. package/public/assets/PlanGraphRoute-CIH9gBuR.js +1 -0
  27. package/public/assets/PlanView-B1hxzFRs.js +2 -0
  28. package/public/assets/PythonUdf-DvgCCueD.js +1 -0
  29. package/public/assets/RetryWaste-uXXu_CyM.js +1 -0
  30. package/public/assets/RowPagination-C-LzWkI5.js +1 -0
  31. package/public/assets/RowStatusCluster-Dbtmte7l.js +1 -0
  32. package/public/assets/ShuffleIO-nALwzC1_.js +1 -0
  33. package/public/assets/Skew-CHMEKgvk.js +1 -0
  34. package/public/assets/SlowHost-yyvjpHk6.js +1 -0
  35. package/public/assets/SmallFiles-y6odJ97n.js +1 -0
  36. package/public/assets/SpeculationWaste-C-SD2LOt.js +1 -0
  37. package/public/assets/Spill-DHTMmOup.js +1 -0
  38. package/public/assets/StageFailed-CQ3DxC9R.js +1 -0
  39. package/public/assets/StageFindingGroup-BgYLyj5q.js +1 -0
  40. package/public/assets/StageHeader-CIETkjVZ.js +1 -0
  41. package/public/assets/StagePill--P7PDd3s.js +1 -0
  42. package/public/assets/StageShape-BIv8vx_o.js +1 -0
  43. package/public/assets/StageSlowness-MMqzERxN.js +1 -0
  44. package/public/assets/Straggler-BgrY7AyW.js +1 -0
  45. package/public/assets/TaskFailures-BHHyKYTs.js +1 -0
  46. package/public/assets/TinyTask-DDScNhCl.js +1 -0
  47. package/public/assets/UnderBroadcast-CGIC04TI.js +1 -0
  48. package/public/assets/WidgetLeadSummary-CXFZP00C.js +1 -0
  49. package/public/assets/button-DbpTz2yk.js +1 -0
  50. package/public/assets/charts-vendor-CtTxwTeu.js +59 -0
  51. package/public/assets/composite-C9Nu2EI9.js +1 -0
  52. package/public/assets/d3-vendor-DNlD2-cz.js +1 -0
  53. package/public/assets/detector-registry-Bp8hrLua.js +2 -0
  54. package/public/assets/downsample-WmNM1qc9.js +1 -0
  55. package/public/assets/finding-anchor-Dr40LkS9.js +1 -0
  56. package/public/assets/findings-of-type-BL2u3RGZ.js +1 -0
  57. package/public/assets/impact-sort-mC5ISgX8.js +1 -0
  58. package/public/assets/inbox-KPU1Gppm.js +1 -0
  59. package/public/assets/index-CaRVPvAT.css +2 -0
  60. package/public/assets/index-fDiwfuoO.js +14 -0
  61. package/public/assets/inertValue-L9VxV0VE.js +1 -0
  62. package/public/assets/layout.worker-CLcBHxVp.js +3 -0
  63. package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
  64. package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
  65. package/public/assets/react-vendor-C6KcUD36.js +9 -0
  66. package/public/assets/select-BHqOqun5.js +1 -0
  67. package/public/assets/toggle-DPeN6aNa.js +1 -0
  68. package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
  69. package/public/assets/usePagedRows-BafD6bEN.js +1 -0
  70. package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
  71. package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
  72. package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
  73. package/public/assets/useSortMode-DjrAN-z4.js +1 -0
  74. package/public/docs/404.html +3 -3
  75. package/public/docs/assets/{app.CnWL6bKV.js → app.1gvzd5Zb.js} +1 -1
  76. package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
  77. package/public/docs/assets/chunks/{VPLocalSearchBox.C0IBKeRQ.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
  78. package/public/docs/assets/chunks/{theme.BH-2HuRf.js → theme.C5lLqUv7.js} +2 -2
  79. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
  80. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
  81. package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.js} +1 -1
  82. package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
  83. package/public/docs/assets/{contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.js → contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js} +1 -1
  84. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
  85. package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
  86. package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.N4hhenrA.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
  87. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
  88. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
  89. package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
  90. package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.lean.js} +1 -1
  91. package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
  92. package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.lean.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.lean.js} +1 -1
  93. package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
  94. package/public/docs/assets/{contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.lean.js → contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.lean.js} +1 -1
  95. package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
  96. package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.DfvbqEUu.lean.js → contributor-guide_architecture_impact-estimation.md.K71YB-Rr.lean.js} +1 -1
  97. package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
  98. package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.lean.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.lean.js} +1 -1
  99. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
  100. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
  101. package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
  102. package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
  103. package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.lean.js} +1 -1
  104. package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
  105. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
  106. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
  107. package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.js} +1 -1
  108. package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.js} +1 -1
  109. package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
  110. package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
  111. package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
  112. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.lean.js} +1 -1
  113. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.js} +1 -1
  114. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.js} +2 -2
  115. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-availability.md.CjimIDBY.lean.js → contributor-guide_architecture_worker-protocol_evidence-availability.md.D3S5cyOW.lean.js} +1 -1
  116. package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
  117. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.lean.js} +1 -1
  118. package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
  119. package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.js +15 -0
  120. package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
  121. package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
  122. package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
  123. package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
  124. package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
  125. package/public/docs/assets/{style.CyK9Ss73.css → style.Cfxqlj0y.css} +1 -1
  126. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
  127. package/public/docs/assets/{user-guide_getting-started_ci-and-automation.md.BEepbDDL.lean.js → user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js} +1 -1
  128. package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
  129. package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.js} +2 -2
  130. package/public/docs/assets/{user-guide_getting-started_tuning-thresholds.md.B_MyjyZm.lean.js → user-guide_getting-started_tuning-thresholds.md.BGVE-wrc.lean.js} +1 -1
  131. package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
  132. package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js → user-guide_mcp-tools_compare-runs.md.BQ_kIptC.js} +11 -6
  133. package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
  134. package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
  135. package/public/docs/assets/{user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.lean.js → user-guide_mcp-tools_diagnose-run.md.azCZXkH8.lean.js} +1 -1
  136. package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
  137. package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.lean.js} +1 -1
  138. package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.js} +2 -1
  139. package/public/docs/assets/{user-guide_mcp-tools_get-finding-evidence.md.rKyu4wts.lean.js → user-guide_mcp-tools_get-finding-evidence.md.CH6FkNLX.lean.js} +1 -1
  140. package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
  141. package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
  142. package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
  143. package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
  144. package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -6
  145. package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -6
  146. package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -6
  147. package/public/docs/contributor-guide/architecture/board-widgets.html +6 -6
  148. package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -6
  149. package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -6
  150. package/public/docs/contributor-guide/architecture/detector-contract.html +6 -6
  151. package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -6
  152. package/public/docs/contributor-guide/architecture/drill-down.html +6 -6
  153. package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -6
  154. package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -6
  155. package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -6
  156. package/public/docs/contributor-guide/architecture/index.html +5 -5
  157. package/public/docs/contributor-guide/architecture/overview.html +6 -6
  158. package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -5
  159. package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -6
  160. package/public/docs/contributor-guide/architecture/state-and-history.html +5 -5
  161. package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -6
  162. package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -5
  163. package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -6
  164. package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -5
  165. package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -6
  166. package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -6
  167. package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -6
  168. package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -6
  169. package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -7
  170. package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -6
  171. package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -6
  172. package/public/docs/contributor-guide/contributing.html +6 -6
  173. package/public/docs/contributor-guide/development-setup.html +8 -8
  174. package/public/docs/contributor-guide/testing.html +9 -6
  175. package/public/docs/hashmap.json +1 -1
  176. package/public/docs/index.html +6 -6
  177. package/public/docs/logo-dark.svg +1 -0
  178. package/public/docs/logo-light.svg +1 -0
  179. package/public/docs/tuning-reference/anti-patterns.html +5 -5
  180. package/public/docs/tuning-reference/aqe.html +5 -5
  181. package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -5
  182. package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -5
  183. package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -5
  184. package/public/docs/tuning-reference/bottleneck-failures.html +5 -5
  185. package/public/docs/tuning-reference/bottleneck-gc.html +5 -5
  186. package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -5
  187. package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -5
  188. package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -5
  189. package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -5
  190. package/public/docs/tuning-reference/bottleneck-skew.html +5 -5
  191. package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -5
  192. package/public/docs/tuning-reference/bottleneck-small-files.html +5 -5
  193. package/public/docs/tuning-reference/bottleneck-spill.html +5 -5
  194. package/public/docs/tuning-reference/bottleneck-straggler.html +5 -5
  195. package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -5
  196. package/public/docs/tuning-reference/bottleneck-utilization.html +5 -5
  197. package/public/docs/tuning-reference/caching.html +5 -5
  198. package/public/docs/tuning-reference/cluster-config.html +5 -5
  199. package/public/docs/tuning-reference/config.html +5 -5
  200. package/public/docs/tuning-reference/data-formats.html +5 -5
  201. package/public/docs/tuning-reference/index.html +5 -5
  202. package/public/docs/tuning-reference/intro.html +5 -5
  203. package/public/docs/tuning-reference/joins.html +5 -5
  204. package/public/docs/tuning-reference/memory-model.html +5 -5
  205. package/public/docs/tuning-reference/metrics.html +5 -5
  206. package/public/docs/tuning-reference/partitioning.html +5 -5
  207. package/public/docs/tuning-reference/pyspark.html +5 -5
  208. package/public/docs/tuning-reference/shuffle.html +5 -5
  209. package/public/docs/tuning-reference/spark-architecture.html +5 -5
  210. package/public/docs/tuning-reference/table-formats.html +5 -5
  211. package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -5
  212. package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -5
  213. package/public/docs/user-guide/alternative-log-retrieval.html +5 -5
  214. package/public/docs/user-guide/getting-started/ci-and-automation.html +16 -11
  215. package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -6
  216. package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -5
  217. package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -7
  218. package/public/docs/user-guide/getting-started.html +5 -5
  219. package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -11
  220. package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -7
  221. package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -6
  222. package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -5
  223. package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -6
  224. package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -5
  225. package/public/docs/user-guide/mcp-tools/get-run-summary.html +5 -5
  226. package/public/docs/user-guide/mcp-tools/list-runs.html +5 -5
  227. package/public/docs/user-guide/mcp-tools.html +6 -6
  228. package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -5
  229. package/public/docs/user-guide/run-comparison.html +6 -6
  230. package/public/docs/user-guide/understanding-findings.html +6 -6
  231. package/public/export-template.html +45 -45
  232. package/public/index.html +8 -7
  233. package/public/sample-runs/sample-run.ndjson.gz +0 -0
  234. package/vendor-core/allocation.js +25 -23
  235. package/vendor-core/analyzer.js +85 -58
  236. package/vendor-core/api-merge-writes.js +2 -0
  237. package/vendor-core/aqe-skew.js +347 -0
  238. package/vendor-core/cli/budgets.js +6 -4
  239. package/vendor-core/cli/collect-run-pair.js +89 -0
  240. package/vendor-core/cli/collect-run-worker.js +16 -0
  241. package/vendor-core/cli/collect-run.js +1 -2
  242. package/vendor-core/cli/native-zstd.js +12 -16
  243. package/vendor-core/comparability.js +234 -0
  244. package/vendor-core/comparison-output.js +15 -7
  245. package/vendor-core/comparison-verdict.js +105 -25
  246. package/vendor-core/core-source-hash.txt +1 -1
  247. package/vendor-core/core-time-series.js +0 -1
  248. package/vendor-core/core-usage-locality.js +1 -1
  249. package/vendor-core/detectors.js +1007 -380
  250. package/vendor-core/docs-config.js +0 -4
  251. package/vendor-core/docs-content/detection/cache.md +2 -1
  252. package/vendor-core/docs-content/detection/cfg.md +19 -11
  253. package/vendor-core/docs-content/detection/cold.md +2 -1
  254. package/vendor-core/docs-content/detection/gc.md +7 -3
  255. package/vendor-core/docs-content/detection/host.md +11 -1
  256. package/vendor-core/docs-content/detection/mem.md +17 -6
  257. package/vendor-core/docs-content/detection/part.md +3 -1
  258. package/vendor-core/docs-content/detection/plan.md +55 -13
  259. package/vendor-core/docs-content/detection/shfl.md +11 -5
  260. package/vendor-core/docs-content/detection/skew.md +47 -1
  261. package/vendor-core/docs-content/detection/slow.md +4 -2
  262. package/vendor-core/docs-content/detection/spec.md +6 -1
  263. package/vendor-core/docs-content/detection/spill.md +6 -3
  264. package/vendor-core/docs-content/detection/strag.md +19 -6
  265. package/vendor-core/docs-content/detection/tiny.md +9 -3
  266. package/vendor-core/effective-conf.js +7 -10
  267. package/vendor-core/efficiency-model.js +2 -2
  268. package/vendor-core/etl-phases.js +1 -2
  269. package/vendor-core/event-handlers.js +175 -57
  270. package/vendor-core/event-schemas.js +21 -16
  271. package/vendor-core/evidence-availability.js +9 -2
  272. package/vendor-core/evidence-report.js +118 -35
  273. package/vendor-core/executor-peaks.js +41 -0
  274. package/vendor-core/export-data.js +5 -5
  275. package/vendor-core/finding-identity.js +78 -0
  276. package/vendor-core/finding-presentation.js +116 -33
  277. package/vendor-core/finding-types.js +88 -21
  278. package/vendor-core/format-utils.js +14 -15
  279. package/vendor-core/html-export.js +1 -1
  280. package/vendor-core/impact-band.js +2 -2
  281. package/vendor-core/impact-format.js +47 -19
  282. package/vendor-core/impact-model.js +26 -15
  283. package/vendor-core/job-groups.js +4 -4
  284. package/vendor-core/mcp-server-factory.js +48 -12
  285. package/vendor-core/mcp-tools.js +179 -24
  286. package/vendor-core/median.js +2 -2
  287. package/vendor-core/nested-loop-join.js +73 -0
  288. package/vendor-core/occupancy.js +1 -2
  289. package/vendor-core/parser-worker.js +1 -1
  290. package/vendor-core/plan-graph-model.js +14 -22
  291. package/vendor-core/plan-node-detail.js +2 -3
  292. package/vendor-core/plan-summary.js +24 -19
  293. package/vendor-core/plan-tree-walk.js +6 -8
  294. package/vendor-core/python-stage.js +12 -1
  295. package/vendor-core/recommendation-rollup.js +13 -12
  296. package/vendor-core/redact.js +52 -46
  297. package/vendor-core/run-aggregates.js +6 -8
  298. package/vendor-core/run-comparison.js +226 -66
  299. package/vendor-core/run-identity.js +12 -0
  300. package/vendor-core/run-interpretation.js +21 -0
  301. package/vendor-core/run-metrics.js +2 -2
  302. package/vendor-core/run-output.js +32 -10
  303. package/vendor-core/run-totals.js +12 -0
  304. package/vendor-core/run-verdict.js +76 -3
  305. package/vendor-core/scaling-sim.js +3 -4
  306. package/vendor-core/snappy-block.js +2 -2
  307. package/vendor-core/spark-conf.js +168 -0
  308. package/vendor-core/sql-stages.js +2 -2
  309. package/vendor-core/stage-alignment.js +2 -12
  310. package/vendor-core/stage-identity.js +58 -3
  311. package/vendor-core/stage-label.js +14 -0
  312. package/vendor-core/stage-plan-nodes.js +17 -3
  313. package/vendor-core/stage-quantiles.js +141 -9
  314. package/vendor-core/stage-structure.js +17 -3
  315. package/vendor-core/threshold-overrides.js +9 -3
  316. package/vendor-core/types.js +58 -21
  317. package/vendor-core/wasted-core-hours.js +0 -1
  318. package/vendor-core/write-targets.js +114 -14
  319. package/vendor-core/zstd-worker-client.js +1 -1
  320. package/vendor-core/zstd-worker.js +1 -1
  321. package/public/assets/AutoscalingChurn-CRA2Mb7F.js +0 -1
  322. package/public/assets/CacheUtilization-Bh9OY_V9.js +0 -1
  323. package/public/assets/CachingOpportunity-oCiQwmTJ.js +0 -1
  324. package/public/assets/ColdStart-BJrtjfmn.js +0 -1
  325. package/public/assets/ConfigAudit-DMvKxySP.js +0 -1
  326. package/public/assets/CoreUsageArea-REC2zsKw.js +0 -1
  327. package/public/assets/Dashboard-BHZ76JCu.js +0 -2
  328. package/public/assets/DisclosureContext-OO7X1HAx.js +0 -1
  329. package/public/assets/DuplicatePlanSubtree-BgG-L-cK.js +0 -1
  330. package/public/assets/ExecutorUtilization-D2KhSVbY.js +0 -1
  331. package/public/assets/GcPressure-D1BTE8qh.js +0 -1
  332. package/public/assets/IncompleteRun-DD40xUpy.js +0 -1
  333. package/public/assets/JobFailures-YwNzCF19.js +0 -1
  334. package/public/assets/MemoryUtilization-9b8ee_3_.js +0 -1
  335. package/public/assets/OverBroadcast-CfctS8a8.js +0 -1
  336. package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
  337. package/public/assets/PartitionSizing-VG8kBgG5.js +0 -1
  338. package/public/assets/PlanExplorer-DmubTAOP.js +0 -1
  339. package/public/assets/PlanGraphRoute-DctPZjS0.js +0 -1
  340. package/public/assets/RetryWaste-CnpM8bB7.js +0 -1
  341. package/public/assets/ShuffleIO-D13vGmas.js +0 -1
  342. package/public/assets/Skew-DlagstYP.js +0 -1
  343. package/public/assets/SlowHost-cSkLRZ_e.js +0 -1
  344. package/public/assets/SmallFiles-B-kERMcq.js +0 -1
  345. package/public/assets/SpeculationWaste-DaysAzXO.js +0 -1
  346. package/public/assets/Spill-H44Gz4US.js +0 -1
  347. package/public/assets/StageFailed-DCfii9h_.js +0 -1
  348. package/public/assets/StageFindingGroup-BXJ0Mj5n.js +0 -1
  349. package/public/assets/StageHeader--oN2J-oD.js +0 -1
  350. package/public/assets/StageShape-IZ80CZiJ.js +0 -1
  351. package/public/assets/StageSlowness--BRIaBc1.js +0 -1
  352. package/public/assets/Straggler-Ctq0Df_o.js +0 -1
  353. package/public/assets/TaskFailures-Bks_gqhL.js +0 -1
  354. package/public/assets/TinyTask-BssfzGFB.js +0 -1
  355. package/public/assets/UnderBroadcast-DsScrxc-.js +0 -1
  356. package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
  357. package/public/assets/finding-anchor-BYW1oz5R.js +0 -1
  358. package/public/assets/impact-sort-xzy0g-Vh.js +0 -1
  359. package/public/assets/index-DhpRGMZc.css +0 -2
  360. package/public/assets/index-DwqkFUFk.js +0 -14
  361. package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
  362. package/public/assets/react-vendor-DfpuPQZf.js +0 -9
  363. package/public/assets/select-C8edjYTq.js +0 -1
  364. package/public/assets/usePagedRows-CsuUFeYx.js +0 -1
  365. package/public/assets/useRecentFiles-BvkKo3JN.js +0 -11
  366. package/public/assets/useSortMode-joX71BZN.js +0 -1
  367. package/public/docs/assets/chunks/@localSearchIndexroot.tE5pz54z.js +0 -1
  368. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
  369. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
  370. package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
  371. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.wulOueeB.lean.js +0 -1
  372. package/public/docs/assets/contributor-guide_architecture_detector-contract.md.N4hhenrA.js +0 -1
  373. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
  374. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
  375. package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.Dp3c40rx.js +0 -1
  376. package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
  377. package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.DfvbqEUu.js +0 -1
  378. package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.Cwm1jHmn.js +0 -1
  379. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
  380. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
  381. package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
  382. package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
  383. package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
  384. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
  385. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
  386. package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
  387. package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.BX1XnFbq.js +0 -1
  388. package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CiQl1MLb.js +0 -1
  389. package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
  390. package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.js +0 -15
  391. package/public/docs/assets/contributor-guide_development-setup.md.DQdzera7.lean.js +0 -1
  392. package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
  393. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.BEepbDDL.js +0 -24
  394. package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
  395. package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
  396. package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
  397. package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
  398. package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
  399. package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.js +0 -1
  400. package/public/docs/assets/user-guide_understanding-findings.md.3C7KCEZO.lean.js +0 -1
  401. /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.CQgn1t_M.lean.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.lean.js} +0 -0
  402. /package/public/docs/assets/{contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.lean.js → contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.lean.js} +0 -0
  403. /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
  404. /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
  405. /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_list-sort-mode.md.BuHKgH0C.lean.js → contributor-guide_architecture_widget-rendering_list-sort-mode.md.37hcZJ7q.lean.js} +0 -0
  406. /package/public/docs/assets/{contributor-guide_architecture_widget-rendering_row-expand-contract.md.ZT89u9f1.lean.js → contributor-guide_architecture_widget-rendering_row-expand-contract.md.mK_VmAWk.lean.js} +0 -0
  407. /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DSVFPpWb.lean.js → contributor-guide_architecture_worker-protocol_core-and-event-validation.md.DVSXn-bb.lean.js} +0 -0
  408. /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
  409. /package/public/docs/assets/{user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.lean.js → user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.lean.js} +0 -0
  410. /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
package/public/index.html CHANGED
@@ -20,14 +20,15 @@
20
20
  document.documentElement.setAttribute('data-theme', 'light');
21
21
  } catch (_) {}
22
22
  </script>
23
- <script type="module" crossorigin src="./assets/index-DwqkFUFk.js"></script>
23
+ <script type="module" crossorigin src="./assets/index-fDiwfuoO.js"></script>
24
24
  <link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-hePW80VL.js">
25
- <link rel="modulepreload" crossorigin href="./assets/charts-vendor-0VMaLVLN.js">
26
- <link rel="modulepreload" crossorigin href="./assets/plan-graph-vendor-BYl-AzN5.js">
27
- <link rel="modulepreload" crossorigin href="./assets/react-vendor-DfpuPQZf.js">
28
- <link rel="modulepreload" crossorigin href="./assets/DisclosureContext-OO7X1HAx.js">
29
- <link rel="stylesheet" crossorigin href="./assets/plan-graph-vendor-DLioOiRN.css">
30
- <link rel="stylesheet" crossorigin href="./assets/index-DhpRGMZc.css">
25
+ <link rel="modulepreload" crossorigin href="./assets/react-vendor-C6KcUD36.js">
26
+ <link rel="modulepreload" crossorigin href="./assets/DisclosureContext-DK1_iz6J.js">
27
+ <link rel="modulepreload" crossorigin href="./assets/inertValue-L9VxV0VE.js">
28
+ <link rel="modulepreload" crossorigin href="./assets/button-DbpTz2yk.js">
29
+ <link rel="modulepreload" crossorigin href="./assets/composite-C9Nu2EI9.js">
30
+ <link rel="modulepreload" crossorigin href="./assets/useScrollLock-BCxn_dMp.js">
31
+ <link rel="stylesheet" crossorigin href="./assets/index-CaRVPvAT.css">
31
32
  </head>
32
33
  <body>
33
34
  <div id="root"></div>
@@ -1,14 +1,15 @@
1
1
  import { computePeakConcurrentExecutorCount } from './core-count.js';
2
2
  import { parseSparkMemoryMB } from './spark-memory.js';
3
+ import { effectiveSparkConf, executorOverheadSettings, } from './spark-conf.js';
3
4
 
4
5
 
5
6
  const MS_PER_HOUR = 3_600_000;
6
7
  const MS_PER_SECOND = 1000;
7
8
  const MIB_PER_GIB = 1024;
8
9
  // Spark's documented floor and factor for the default executor memory overhead
9
- // (spark.executor.memoryOverhead = max(factor * executor memory, 384 MiB)).
10
- const MIN_OVERHEAD_MIB = 384;
11
- const DEFAULT_OVERHEAD_FACTOR = 0.1;
10
+ // (spark.executor.memoryOverhead = max(factor * executor memory, 384 MiB)), for a run whose
11
+ // Spark version does not read the factor or minimum properties.
12
+ const OVERHEAD_FALLBACK = { floorMB: 384, floorPct: 0.1 };
12
13
 
13
14
 
14
15
   
@@ -36,7 +37,7 @@ const DEFAULT_OVERHEAD_FACTOR = 0.1;
36
37
 
37
38
 
38
39
 
39
-
40
+
40
41
 
41
42
 
42
43
 
@@ -55,47 +56,48 @@ export function lastObservedTimestamp(input ) {
55
56
  return last;
56
57
  }
57
58
 
58
- // Spark's default executor memory when spark.executor.memory is unset.
59
- const DEFAULT_EXECUTOR_MEMORY_MIB = 1024;
60
-
61
59
  // One container's memory in MiB, as Spark requests it from the cluster manager: executor heap,
62
- // plus overhead, plus off-heap and PySpark worker memory when configured. Null when the log
63
- // records no Spark properties (nothing to tell a default from a missing config) or a memory key it
64
- // does record cannot be read.
60
+ // plus overhead, plus off-heap and PySpark worker memory when configured. Every setting is read
61
+ // from the run's effective conf (the logged value, else Spark's default for its version). Null when
62
+ // the log records no Spark properties (nothing to tell a default from a missing config) or a memory
63
+ // key it does record cannot be read.
65
64
  function executorMemoryMiB(app ) {
66
65
  const config = app?.config;
67
66
  if (config == null) return null;
67
+ const layers = { sparkVersion: app?.sparkVersion, properties: config };
68
+ const conf = (key ) => effectiveSparkConf(layers, key)?.value;
68
69
  // undefined: key absent; null: present but unreadable.
69
- const mib = (key ) => (config[key] == null ? undefined : parseSparkMemoryMB(config[key]));
70
- const heap = mib('spark.executor.memory') ?? (config['spark.executor.memory'] == null ? DEFAULT_EXECUTOR_MEMORY_MIB : null);
70
+ const mib = (key ) => {
71
+ const value = conf(key);
72
+ return value === undefined ? undefined : parseSparkMemoryMB(value);
73
+ };
74
+ const heap = mib('spark.executor.memory');
71
75
  if (heap == null) return null;
72
76
 
73
77
  let overhead = mib('spark.executor.memoryOverhead');
74
78
  if (overhead === undefined) overhead = mib('spark.yarn.executor.memoryOverhead'); // legacy key
75
79
  if (overhead === undefined) {
76
- const factor = Number.parseFloat(config['spark.executor.memoryOverheadFactor'] ?? '');
77
- overhead = Math.max(MIN_OVERHEAD_MIB, Math.round(heap * (Number.isFinite(factor) && factor > 0 ? factor : DEFAULT_OVERHEAD_FACTOR)));
80
+ const { minMB, factor } = executorOverheadSettings(layers, OVERHEAD_FALLBACK);
81
+ overhead = Math.max(minMB, Math.round(heap * factor));
78
82
  }
79
- const offHeap = String(config['spark.memory.offHeap.enabled']).toLowerCase() === 'true' ? mib('spark.memory.offHeap.size') ?? 0 : 0;
83
+ const offHeap = conf('spark.memory.offHeap.enabled')?.toLowerCase() === 'true' ? mib('spark.memory.offHeap.size') ?? 0 : 0;
80
84
  const pyspark = mib('spark.executor.pyspark.memory') ?? 0;
81
85
  if (overhead === null || offHeap === null || pyspark === null) return null;
82
86
  return heap + overhead + offHeap + pyspark;
83
87
  }
84
88
 
89
+ // The logged `spark.dynamicAllocation.enabled`: a value the app set. Spark's default (off) is not a
90
+ // logged key, so a run that never set it reads null.
85
91
  function loggedDynamicAllocation(app ) {
86
- const raw = app?.config?.['spark.dynamicAllocation.enabled'];
87
- return raw == null ? null : raw.trim().toLowerCase() === 'true' ? 'on' : 'off';
92
+ const effective = effectiveSparkConf({ sparkVersion: app?.sparkVersion, properties: app?.config }, 'spark.dynamicAllocation.enabled');
93
+ return effective == null || effective.source === 'default' ? null : effective.value.toLowerCase() === 'true' ? 'on' : 'off';
88
94
  }
89
95
 
90
96
  /** Allocated core-hours and memory GiB-hours from the executor lifecycle: each executor counts
91
97
  * from its ExecutorAdded timestamp to its first later ExecutorRemoved timestamp. One with no
92
98
  * removal closes at the application end when the log has one, else at the last timestamp the log
93
99
  * records (a cut-off log). Cores are the ExecutorAdded event's Total Cores, else
94
- * spark.executor.cores; memory per executor is spark.executor.memory (default 1g) plus the
95
- * overhead (spark.executor.memoryOverhead, else the legacy spark.yarn.executor.memoryOverhead,
96
- * else the larger of 384 MiB and spark.executor.memoryOverheadFactor, default 0.1, times the
97
- * memory), plus spark.memory.offHeap.size when spark.memory.offHeap.enabled is true, plus
98
- * spark.executor.pyspark.memory.
100
+ * spark.executor.cores; memory per executor is the container Spark requests (executorMemoryMiB).
99
101
  * The executor counts and seconds come from the same alive intervals.
100
102
  * Null, never 0, for a figure whose inputs the log lacks. */
101
103
  export function computeAllocation(input ) {
@@ -151,7 +153,7 @@ function aliveIntervals(input ) {
151
153
  if (times) times.push(e.timestamp); else removedAt.set(e.executorId, [e.timestamp]);
152
154
  }
153
155
  const closeAt = input.app?.endTime ?? lastObservedTimestamp(input);
154
- const configuredCores = Number.parseInt(input.app?.config?.['spark.executor.cores'] ?? '', 10);
156
+ const configuredCores = Number.parseInt(effectiveSparkConf({ sparkVersion: input.app?.sparkVersion, properties: input.app?.config }, 'spark.executor.cores')?.value ?? '', 10);
155
157
  const out = [];
156
158
  const seen = new Set ();
157
159
  for (const e of input.executors.added) {
@@ -1,11 +1,12 @@
1
- import { DETECTORS, ENTRY_BY_TYPE, } from './detectors.js';
1
+ import { DETECTORS, ENTRY_BY_TYPE, hasStageOutsideSql, skewThresholdsFor, } from './detectors.js';
2
2
  import { effectiveThresholds, findingTunedThresholds, overridesFor, tunedThresholdsNote } from './threshold-overrides.js';
3
3
  import { computePeakConcurrentCores } from './core-count.js';
4
4
  import { assertNever } from './assert-never.js';
5
5
  import { estimateImpact, } from './impact-estimator.js';
6
6
  import { computeOccupancy, } from './occupancy.js';
7
7
  import { deriveImpactBand, IMPACT_FLOOR_PCT_CRIT, IMPACT_FLOOR_PCT_WARN, } from './impact-band.js';
8
- import { IMPACT_BAND_ORDER } from './format-utils.js';
8
+ import { IMPACT_BAND_ORDER, MS_PER_CORE_HOUR } from './format-utils.js';
9
+ import { computeWastedCoreHours } from './wasted-core-hours.js';
9
10
 
10
11
 
11
12
 
@@ -17,7 +18,7 @@ const detectors = DETECTORS;
17
18
 
18
19
 
19
20
 
20
-
21
+
21
22
 
22
23
 
23
24
 
@@ -33,8 +34,8 @@ function fnv1a(str ) {
33
34
  return (h >>> 0).toString(16).padStart(8, '0');
34
35
  }
35
36
 
36
- // The id hash's discriminator slots, in the order it has always joined them: reordering or renaming
37
- // one changes every finding id, which needs an EVIDENCE_SCHEMA_VERSION bump.
37
+ // The id hash's discriminator slots, in join order: reordering or renaming one changes every
38
+ // finding id, which needs an EVIDENCE_SCHEMA_VERSION bump.
38
39
  const DISCRIMINATOR_SLOTS = [
39
40
  'host', 'executorId', 'rule', 'variant', 'dimension',
40
41
  'direction', 'nodeName', 'rootName', 'subtreeSize', 'groupIndex', 'largerSideBytes',
@@ -43,16 +44,11 @@ const DISCRIMINATOR_SLOTS = [
43
44
 
44
45
 
45
46
  // Per type, the fields that tell apart sibling findings sharing one location and metric; without
46
- // them those siblings hash to one id:
47
- // slowHost (host), memoryUtilization (executorId), partitionSizing (rule);
48
- // cacheUtilization (rddId+variant), cachingOpportunity (relation/format for leaf,
49
- // operator+relation for composite, executionIds as last resort);
50
- // smallFiles (direction/nodeName), duplicatePlanSubtree (groupIndex is the real
51
- // uniqueness guarantee: rootName+subtreeSize can collide across groups),
52
- // underBroadcast (value+largerSideBytes per node/side).
53
- // memoryUtilization leaves out `rule`: one heap band per executor, so executorId is already
54
- // unique and folding rule in risks id churn if band logic changes. partitionSizing keeps
55
- // `rule`: a stage can emit several rules at once sharing stageId+metric.
47
+ // them those siblings hash to one id (see detector-contract.md, Finding ids). Notes:
48
+ // duplicatePlanSubtree's groupIndex is the real uniqueness guarantee (rootName+subtreeSize can
49
+ // collide across groups); memoryUtilization leaves out `rule` because its one heap band sits on
50
+ // the busiest executor, so executorId is already unique; partitionSizing keeps `rule` because a
51
+ // stage can emit several rules at once sharing stageId+metric.
56
52
  const ID_DISCRIMINATORS = {
57
53
  skew: [], stageShape: ['rule'], shuffle: [], partitionSizing: ['rule'], spill: [], gc: ['direction'],
58
54
  slowHost: ['host', 'executorId', 'variant', 'dimension'], stageSlowness: [], stageFailed: ['variant'],
@@ -62,6 +58,8 @@ const ID_DISCRIMINATORS
62
58
  cachingOpportunity: ['variant', 'relation', 'format', 'operator', 'executionIds'],
63
59
  jobFailureRate: [], configAudit: [],
64
60
  duplicatePlanSubtree: ['rootName', 'subtreeSize', 'groupIndex'], smallFiles: ['direction', 'nodeName'],
61
+ pythonUdf: [],
62
+ nestedLoopJoin: ['nodeName'],
65
63
  underBroadcast: ['largerSideBytes'], overBroadcast: [],
66
64
  };
67
65
 
@@ -88,35 +86,6 @@ export function findingId(f ) {
88
86
  return fnv1a(`${f.type}|${locationKey(f)}|${f.metric ?? ''}|${f.value ?? f.valueText ?? ''}|${disc}`);
89
87
  }
90
88
 
91
- // skew (either branch) and straggler both claim the stage's replayed tail recovery
92
- // (tailReplayRecoveryMs via tailRecoveryMs): the same slow-task tail reported by two detectors
93
- // (see "Overlap caveat: skew / straggler" in impact-estimation/caveats-tuning-and-coverage.md). skew's branch only changes
94
- // the fallback single-task delta on a stage without the replay, so every skew + straggler pair
95
- // on a stage is flagged. Flags both sides via validationRequired (rather than suppressing
96
- // either) so neither finding's own diagnostic value is lost; the flag rides the same
97
- // confidence-caveat UI a reader already sees before trusting either finding's magnitude.
98
- function overlapNote(otherType ) {
99
- return `This overlaps with the ${otherType} finding on this stage: both measure the same slow-task tail, so don't add their recoverable-time figures together.`;
100
- }
101
-
102
- function flagSkewStragglerOverlap(findings ) {
103
- const skewStages = new Set(
104
- findings.filter((f) => f.type === 'skew' && f.stageId != null).map((f) => f.stageId),
105
- );
106
- if (skewStages.size === 0) return;
107
- const stragglerStages = new Set(
108
- findings.filter((f) => f.type === 'straggler' && f.stageId != null).map((f) => f.stageId),
109
- );
110
- const overlapStages = new Set([...skewStages].filter((id) => stragglerStages.has(id)));
111
- if (overlapStages.size === 0) return;
112
- for (const f of findings) {
113
- if (f.stageId == null || !overlapStages.has(f.stageId)) continue;
114
- const note = f.type === 'skew' ? overlapNote('straggler') : f.type === 'straggler' ? overlapNote('skew') : null;
115
- if (!note) continue;
116
- f.validationRequired = [f.validationRequired, note].filter(Boolean).join(' ');
117
- }
118
- }
119
-
120
89
  function push(out , entry , result , tuned = null) {
121
90
  if (!result) return;
122
91
  const detectorVersion = entry.version ?? 1;
@@ -176,6 +145,57 @@ function applySuppression(out ) {
176
145
  return out.filter((f) => f.stageId == null || !dropped.get(f.type)?.has(f.stageId));
177
146
  }
178
147
 
148
+ // Advice to lower spark.executor.memory (over-provisioned heap, low GC, idle memory-time) contradicts
149
+ // advice to raise it (high GC, spill, a GC-bound straggler tail) where a stage is short of memory.
150
+ // A stage-level lowering finding on the same stage as raising advice is dropped. A run-level one
151
+ // (heap, idle memory-time) stays, since other stages may well have memory to spare, but its advice
152
+ // to lower memory is replaced by a note naming the stages that ask for more.
153
+ const EXECUTOR_MEMORY_KEY = 'spark.executor.memory';
154
+
155
+ function changesExecutorMemory(f , direction ) {
156
+ return (f.remediation ?? []).some((r) => r.kind === 'conf' && r.key === EXECUTOR_MEMORY_KEY && r.direction === direction);
157
+ }
158
+
159
+ function reconcileExecutorMemoryAdvice(out ) {
160
+ const raising = out.filter((f) => changesExecutorMemory(f, 'increase'));
161
+ if (raising.length === 0) return out;
162
+ const raisingStages = new Set(raising.flatMap((f) => (f.stageId != null ? [f.stageId] : [])));
163
+ const stageList = [...raisingStages].sort((a, b) => a - b).join(', ');
164
+ const conflict = raisingStages.size > 0
165
+ ? `Stage${raisingStages.size === 1 ? '' : 's'} ${stageList} ask${raisingStages.size === 1 ? 's' : ''} for more executor memory, so confirm before lowering it.`
166
+ : 'Other findings ask for more executor memory, so confirm before lowering it.';
167
+ const reconciled = [];
168
+ for (const f of out) {
169
+ if (!changesExecutorMemory(f, 'decrease') || changesExecutorMemory(f, 'increase')) { reconciled.push(f); continue; }
170
+ if (f.stageId != null) {
171
+ if (!raisingStages.has(f.stageId)) reconciled.push(f);
172
+ continue;
173
+ }
174
+ reconciled.push({
175
+ ...f,
176
+ recommendation: `${f.recommendation ?? ''} ${conflict}`.trim(),
177
+ remediation: (f.remediation ?? []).filter((r) => !(r.kind === 'conf' && r.key === EXECUTOR_MEMORY_KEY && r.direction === 'decrease')),
178
+ });
179
+ }
180
+ return reconciled;
181
+ }
182
+
183
+ // The run's idle core-ms (the Wasted core-hours figure), the ceiling for one stage's idle claim.
184
+ function runIdleCoreMs(
185
+ app ,
186
+ executorsAdded ,
187
+ executorsRemoved ,
188
+ runAggregates ,
189
+ ) {
190
+ const { wastedCoreHours } = computeWastedCoreHours(
191
+ app,
192
+ executorsAdded ,
193
+ runAggregates,
194
+ executorsRemoved ,
195
+ );
196
+ return wastedCoreHours == null ? null : wastedCoreHours * MS_PER_CORE_HOUR;
197
+ }
198
+
179
199
  // `app` widened to `SparkAppInfo | null` to match real callers (AppModel.app is
180
200
  // nullable at the type level); every detector below tolerates a null app.
181
201
  export function analyze(
@@ -203,6 +223,7 @@ export function analyze(
203
223
  const impact = {
204
224
  stages, totalCores, sql,
205
225
  occupancy: computeOccupancy(stages , totalCores),
226
+ runIdleCoreMs: runIdleCoreMs(app, executorsAdded, executorsRemoved, runAggregates),
206
227
  };
207
228
  // The one cast from the posted-model types to the detector-side shapes: types.ts's Stage and
208
229
  // SqlExecution carry a catch-all index signature, while every field DetectorStage/DetectorSqlExec
@@ -211,6 +232,7 @@ export function analyze(
211
232
  app, jobs, executorsAdded, executorsRemoved, runAggregates, impact,
212
233
  stages: stages ,
213
234
  sql: sql ,
235
+ skewThresholds: skewThresholdsFor(thresholds),
214
236
  };
215
237
  const out = [];
216
238
  for (const d of detectors) {
@@ -238,11 +260,10 @@ export function analyze(
238
260
  assertNever(d);
239
261
  }
240
262
  }
241
- const findings = applySuppression(out);
263
+ const findings = reconcileExecutorMemoryAdvice(applySuppression(out));
242
264
  estimateImpact(findings, impact);
243
265
  noteTunedThresholds(findings);
244
266
  deriveImpactBand(findings, app, thresholds ? (type) => bandFloors(type, thresholds) : undefined);
245
- flagSkewStragglerOverlap(findings);
246
267
  // Ascending IMPACT_BAND_ORDER (critical 0 -> info 2) puts the worst band first;
247
268
  // stable sort keeps DETECTORS declaration order within a band.
248
269
  findings.sort((a, b) => IMPACT_BAND_ORDER[a.impactBand] - IMPACT_BAND_ORDER[b.impactBand]);
@@ -250,14 +271,17 @@ export function analyze(
250
271
  }
251
272
 
252
273
  // Memoizes auditConfig by `app` identity (like evidence-report.ts's jsonCache) so config detectors
253
- // don't re-run when both the export and the report path audit the same app. WeakMap can't key on
254
- // `null`, so that case skips the cache. Returns a fresh copy each call so a caller's in-place
255
- // mutation (e.g. `.sort()`) can't corrupt the cached array.
256
- const auditConfigCache = new WeakMap ();
274
+ // don't re-run when both the export and the report path audit the same app. The one stage-dependent
275
+ // check reads only whether any stage ran outside SQL, so that flag is part of the cache entry: a
276
+ // hit with a different flag recomputes. WeakMap can't key on `null`, so that case skips the cache.
277
+ // Returns a fresh copy each call so a caller's in-place mutation (e.g. `.sort()`) can't corrupt the
278
+ // cached array.
279
+ const auditConfigCache = new WeakMap ();
257
280
 
258
- function computeAuditConfig(app ) {
281
+ function computeAuditConfig(app , stages ) {
259
282
  const out = [];
260
- for (const d of detectors) if (d.scope === 'config') push(out, d, d.withThresholds()({ app }));
283
+ const target = { app, stages: stages };
284
+ for (const d of detectors) if (d.scope === 'config') push(out, d, d.withThresholds()(target));
261
285
  // configAudit's estimate is unconditionally costOnly('none'): needs no stages/totalCores, so an
262
286
  // empty context gives parity with analyze().
263
287
  estimateImpact(out, { stages: new Map(), occupancy: new Map(), totalCores: 0 });
@@ -265,11 +289,14 @@ function computeAuditConfig(app ) {
265
289
  return out.map((f) => ({ ...f, stageId: f.stageId ?? null }));
266
290
  }
267
291
 
268
- export function auditConfig(app ) {
269
- if (app === null) return computeAuditConfig(app);
292
+ /** The configuration findings for a run. `stages` lets checks that apply only to some kinds of
293
+ * work (the serializer note needs RDD stages) see the run's work; without it they stay silent. */
294
+ export function auditConfig(app , stages ) {
295
+ if (app === null) return computeAuditConfig(app, stages);
296
+ const rddWork = hasStageOutsideSql(stages );
270
297
  const cached = auditConfigCache.get(app);
271
- if (cached) return cached.slice();
272
- const result = computeAuditConfig(app);
273
- auditConfigCache.set(app, result);
274
- return result.slice();
298
+ if (cached?.rddWork === rddWork) return cached.findings.slice();
299
+ const findings = computeAuditConfig(app, stages);
300
+ auditConfigCache.set(app, { rddWork, findings });
301
+ return findings.slice();
275
302
  }
@@ -74,6 +74,8 @@ export function apiMergeWrites(sql )
74
74
  kind: resolved?.kind ?? null,
75
75
  target: resolved?.target ?? null,
76
76
  outputRows: null,
77
+ outputRowsSource: null,
78
+ outputBytes: null,
77
79
  mergeRows: null,
78
80
  raw: `Delta MERGE operation, executions ${span}${group.unclean ? ` (${group.unclean})` : ''}`,
79
81
  };