sparkforensics-server 0.5.2 → 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 (445) 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/instrument-sans-latin-ext-wdth-normal-C5E2Gvlv.woff2 +0 -0
  63. package/public/assets/instrument-sans-latin-wdth-normal-BVScPF0l.woff2 +0 -0
  64. package/public/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
  65. package/public/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
  66. package/public/assets/layout.worker-CLcBHxVp.js +3 -0
  67. package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
  68. package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
  69. package/public/assets/react-vendor-C6KcUD36.js +9 -0
  70. package/public/assets/select-BHqOqun5.js +1 -0
  71. package/public/assets/toggle-DPeN6aNa.js +1 -0
  72. package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
  73. package/public/assets/usePagedRows-BafD6bEN.js +1 -0
  74. package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
  75. package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
  76. package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
  77. package/public/assets/useSortMode-DjrAN-z4.js +1 -0
  78. package/public/docs/404.html +3 -7
  79. package/public/docs/assets/{app.eYTPqTeq.js → app.1gvzd5Zb.js} +1 -1
  80. package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
  81. package/public/docs/assets/chunks/{VPLocalSearchBox.DsZrQKQR.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
  82. package/public/docs/assets/chunks/{theme.DsTNE2pE.js → theme.C5lLqUv7.js} +2 -2
  83. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
  84. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
  85. package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.js} +1 -1
  86. package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
  87. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js +1 -0
  88. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
  89. package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
  90. package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.wj6Et6UD.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
  91. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
  92. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
  93. package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
  94. package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.lean.js} +1 -1
  95. package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
  96. 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
  97. package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
  98. 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
  99. package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
  100. package/public/docs/assets/{contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.lean.js → contributor-guide_architecture_impact-estimation.md.K71YB-Rr.lean.js} +1 -1
  101. package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
  102. package/public/docs/assets/{contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.lean.js → contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.lean.js} +1 -1
  103. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
  104. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
  105. package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
  106. package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
  107. 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
  108. package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
  109. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
  110. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
  111. 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
  112. 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
  113. package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
  114. package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
  115. package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
  116. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.lean.js} +1 -1
  117. 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
  118. 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
  119. 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
  120. package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
  121. package/public/docs/assets/{contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.lean.js → contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.lean.js} +1 -1
  122. package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
  123. package/public/docs/assets/{contributor-guide_development-setup.md.D9bu4j_c.js → contributor-guide_development-setup.md.B21ZTDhn.js} +3 -3
  124. package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
  125. package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
  126. package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
  127. package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
  128. package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
  129. package/public/docs/assets/instrument-sans-latin-ext-wdth-normal.C5E2Gvlv.woff2 +0 -0
  130. package/public/docs/assets/instrument-sans-latin-wdth-normal.BVScPF0l.woff2 +0 -0
  131. package/public/docs/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
  132. package/public/docs/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
  133. package/public/docs/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
  134. package/public/docs/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
  135. package/public/docs/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
  136. package/public/docs/assets/style.Cfxqlj0y.css +1 -0
  137. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
  138. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js +1 -0
  139. package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
  140. 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
  141. 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
  142. package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
  143. 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
  144. package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
  145. package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
  146. 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
  147. package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
  148. 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
  149. 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
  150. 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
  151. package/public/docs/assets/{user-guide_mcp-tools_get-run-summary.md.DpxZ4ZNp.js → user-guide_mcp-tools_get-run-summary.md.EhaIsele.js} +1 -1
  152. package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
  153. package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
  154. package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
  155. package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
  156. package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -10
  157. package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -10
  158. package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -10
  159. package/public/docs/contributor-guide/architecture/board-widgets.html +6 -10
  160. package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -10
  161. package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -10
  162. package/public/docs/contributor-guide/architecture/detector-contract.html +6 -10
  163. package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -10
  164. package/public/docs/contributor-guide/architecture/drill-down.html +6 -10
  165. package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -10
  166. package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -10
  167. package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -10
  168. package/public/docs/contributor-guide/architecture/index.html +5 -9
  169. package/public/docs/contributor-guide/architecture/overview.html +6 -10
  170. package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -9
  171. package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -10
  172. package/public/docs/contributor-guide/architecture/state-and-history.html +5 -9
  173. package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -10
  174. package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -9
  175. package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -10
  176. package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -9
  177. package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -10
  178. package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -10
  179. package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -10
  180. package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -10
  181. package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -11
  182. package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -10
  183. package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -10
  184. package/public/docs/contributor-guide/contributing.html +6 -10
  185. package/public/docs/contributor-guide/development-setup.html +8 -12
  186. package/public/docs/contributor-guide/testing.html +9 -10
  187. package/public/docs/favicon.svg +2 -2
  188. package/public/docs/hashmap.json +1 -1
  189. package/public/docs/index.html +6 -10
  190. package/public/docs/logo-dark.svg +1 -0
  191. package/public/docs/logo-light.svg +1 -0
  192. package/public/docs/tuning-reference/anti-patterns.html +5 -9
  193. package/public/docs/tuning-reference/aqe.html +5 -9
  194. package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -9
  195. package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -9
  196. package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -9
  197. package/public/docs/tuning-reference/bottleneck-failures.html +5 -9
  198. package/public/docs/tuning-reference/bottleneck-gc.html +5 -9
  199. package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -9
  200. package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -9
  201. package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -9
  202. package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -9
  203. package/public/docs/tuning-reference/bottleneck-skew.html +5 -9
  204. package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -9
  205. package/public/docs/tuning-reference/bottleneck-small-files.html +5 -9
  206. package/public/docs/tuning-reference/bottleneck-spill.html +5 -9
  207. package/public/docs/tuning-reference/bottleneck-straggler.html +5 -9
  208. package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -9
  209. package/public/docs/tuning-reference/bottleneck-utilization.html +5 -9
  210. package/public/docs/tuning-reference/caching.html +5 -9
  211. package/public/docs/tuning-reference/cluster-config.html +5 -9
  212. package/public/docs/tuning-reference/config.html +5 -9
  213. package/public/docs/tuning-reference/data-formats.html +5 -9
  214. package/public/docs/tuning-reference/index.html +5 -9
  215. package/public/docs/tuning-reference/intro.html +5 -9
  216. package/public/docs/tuning-reference/joins.html +5 -9
  217. package/public/docs/tuning-reference/memory-model.html +5 -9
  218. package/public/docs/tuning-reference/metrics.html +5 -9
  219. package/public/docs/tuning-reference/partitioning.html +5 -9
  220. package/public/docs/tuning-reference/pyspark.html +5 -9
  221. package/public/docs/tuning-reference/shuffle.html +5 -9
  222. package/public/docs/tuning-reference/spark-architecture.html +5 -9
  223. package/public/docs/tuning-reference/table-formats.html +5 -9
  224. package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -9
  225. package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -9
  226. package/public/docs/user-guide/alternative-log-retrieval.html +5 -9
  227. package/public/docs/user-guide/getting-started/ci-and-automation.html +17 -15
  228. package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -10
  229. package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -9
  230. package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -11
  231. package/public/docs/user-guide/getting-started.html +5 -9
  232. package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -15
  233. package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -11
  234. package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -10
  235. package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -9
  236. package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -10
  237. package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -9
  238. package/public/docs/user-guide/mcp-tools/get-run-summary.html +6 -10
  239. package/public/docs/user-guide/mcp-tools/list-runs.html +5 -9
  240. package/public/docs/user-guide/mcp-tools.html +6 -10
  241. package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -9
  242. package/public/docs/user-guide/run-comparison.html +6 -10
  243. package/public/docs/user-guide/understanding-findings.html +6 -10
  244. package/public/export-template.html +46 -46
  245. package/public/favicon.svg +2 -2
  246. package/public/index.html +8 -10
  247. package/public/sample-runs/sample-run.ndjson.gz +0 -0
  248. package/vendor-core/allocation.js +126 -39
  249. package/vendor-core/analyzer.js +85 -58
  250. package/vendor-core/api-merge-writes.js +3 -0
  251. package/vendor-core/aqe-skew.js +347 -0
  252. package/vendor-core/cli/budgets.js +6 -4
  253. package/vendor-core/cli/collect-run-pair.js +89 -0
  254. package/vendor-core/cli/collect-run-worker.js +16 -0
  255. package/vendor-core/cli/collect-run.js +1 -2
  256. package/vendor-core/cli/native-zstd.js +12 -16
  257. package/vendor-core/comparability.js +234 -0
  258. package/vendor-core/comparison-output.js +15 -7
  259. package/vendor-core/comparison-verdict.js +105 -25
  260. package/vendor-core/core-source-hash.txt +1 -1
  261. package/vendor-core/core-time-series.js +0 -1
  262. package/vendor-core/core-usage-locality.js +1 -1
  263. package/vendor-core/delta-log-paths.js +10 -1
  264. package/vendor-core/detectors.js +1078 -416
  265. package/vendor-core/docs-config.js +0 -4
  266. package/vendor-core/docs-content/detection/cache.md +2 -1
  267. package/vendor-core/docs-content/detection/cfg.md +19 -11
  268. package/vendor-core/docs-content/detection/cold.md +2 -1
  269. package/vendor-core/docs-content/detection/gc.md +7 -3
  270. package/vendor-core/docs-content/detection/host.md +11 -1
  271. package/vendor-core/docs-content/detection/mem.md +17 -6
  272. package/vendor-core/docs-content/detection/part.md +3 -1
  273. package/vendor-core/docs-content/detection/plan.md +55 -13
  274. package/vendor-core/docs-content/detection/shfl.md +11 -5
  275. package/vendor-core/docs-content/detection/skew.md +48 -1
  276. package/vendor-core/docs-content/detection/slow.md +4 -2
  277. package/vendor-core/docs-content/detection/spec.md +6 -1
  278. package/vendor-core/docs-content/detection/spill.md +6 -3
  279. package/vendor-core/docs-content/detection/strag.md +19 -6
  280. package/vendor-core/docs-content/detection/tiny.md +9 -3
  281. package/vendor-core/docs-content/detection/util.md +6 -2
  282. package/vendor-core/effective-conf.js +7 -10
  283. package/vendor-core/efficiency-model.js +24 -16
  284. package/vendor-core/etl-phases.js +1 -2
  285. package/vendor-core/event-handlers.js +175 -57
  286. package/vendor-core/event-schemas.js +21 -16
  287. package/vendor-core/evidence-availability.js +9 -2
  288. package/vendor-core/evidence-report.js +118 -35
  289. package/vendor-core/executor-peaks.js +41 -0
  290. package/vendor-core/export-data.js +5 -5
  291. package/vendor-core/finding-identity.js +78 -0
  292. package/vendor-core/finding-presentation.js +129 -39
  293. package/vendor-core/finding-types.js +108 -30
  294. package/vendor-core/format-utils.js +14 -15
  295. package/vendor-core/html-export.js +1 -1
  296. package/vendor-core/impact-band.js +2 -2
  297. package/vendor-core/impact-format.js +47 -19
  298. package/vendor-core/impact-model.js +28 -17
  299. package/vendor-core/job-groups.js +4 -4
  300. package/vendor-core/mcp-server-factory.js +48 -12
  301. package/vendor-core/mcp-tools.js +179 -24
  302. package/vendor-core/median.js +2 -2
  303. package/vendor-core/nested-loop-join.js +73 -0
  304. package/vendor-core/occupancy.js +1 -2
  305. package/vendor-core/parser-worker.js +1 -1
  306. package/vendor-core/plan-graph-model.js +14 -22
  307. package/vendor-core/plan-node-detail.js +2 -3
  308. package/vendor-core/plan-summary.js +24 -19
  309. package/vendor-core/plan-tree-walk.js +6 -8
  310. package/vendor-core/python-stage.js +12 -1
  311. package/vendor-core/recommendation-rollup.js +13 -12
  312. package/vendor-core/redact.js +52 -46
  313. package/vendor-core/remediation.js +10 -5
  314. package/vendor-core/run-aggregates.js +6 -8
  315. package/vendor-core/run-comparison.js +226 -66
  316. package/vendor-core/run-identity.js +12 -0
  317. package/vendor-core/run-interpretation.js +21 -0
  318. package/vendor-core/run-metrics.js +2 -2
  319. package/vendor-core/run-output.js +44 -11
  320. package/vendor-core/run-totals.js +12 -0
  321. package/vendor-core/run-verdict.js +76 -3
  322. package/vendor-core/scaling-sim.js +3 -4
  323. package/vendor-core/snappy-block.js +2 -2
  324. package/vendor-core/spark-conf.js +168 -0
  325. package/vendor-core/sql-stages.js +2 -2
  326. package/vendor-core/stage-alignment.js +2 -12
  327. package/vendor-core/stage-identity.js +58 -3
  328. package/vendor-core/stage-label.js +14 -0
  329. package/vendor-core/stage-plan-nodes.js +17 -3
  330. package/vendor-core/stage-quantiles.js +141 -9
  331. package/vendor-core/stage-structure.js +17 -3
  332. package/vendor-core/threshold-overrides.js +9 -3
  333. package/vendor-core/types.js +70 -23
  334. package/vendor-core/wall-clock.js +8 -0
  335. package/vendor-core/wasted-core-hours.js +12 -12
  336. package/vendor-core/write-targets.js +146 -14
  337. package/vendor-core/zstd-worker-client.js +1 -1
  338. package/vendor-core/zstd-worker.js +1 -1
  339. package/public/assets/AutoscalingChurn-8t3U3isq.js +0 -1
  340. package/public/assets/CacheUtilization-CJs9tTum.js +0 -1
  341. package/public/assets/CachingOpportunity-D1NcHs0V.js +0 -1
  342. package/public/assets/ColdStart-CdRJ9gD8.js +0 -1
  343. package/public/assets/ConfigAudit-B5Gbe5js.js +0 -1
  344. package/public/assets/CoreUsageArea-a--NTRGY.js +0 -1
  345. package/public/assets/Dashboard-C1hNeX49.js +0 -2
  346. package/public/assets/DisclosureContext-ZpE6CkHx.js +0 -1
  347. package/public/assets/DuplicatePlanSubtree-dobXdz7E.js +0 -1
  348. package/public/assets/ExecutorUtilization-D9grwi7t.js +0 -1
  349. package/public/assets/GcPressure-8-G2ri10.js +0 -1
  350. package/public/assets/IncompleteRun-B91lky7a.js +0 -1
  351. package/public/assets/JobFailures-BsWvBMyJ.js +0 -1
  352. package/public/assets/MemoryUtilization-BM5schZI.js +0 -1
  353. package/public/assets/OverBroadcast-DdN8JIJH.js +0 -1
  354. package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
  355. package/public/assets/PartitionSizing-CY5HDYtp.js +0 -1
  356. package/public/assets/PlanExplorer-DgHCDBD_.js +0 -1
  357. package/public/assets/PlanGraphRoute-DH3KJb8j.js +0 -1
  358. package/public/assets/RetryWaste-DOnE9vGF.js +0 -1
  359. package/public/assets/ShuffleIO-MMnDESkF.js +0 -1
  360. package/public/assets/Skew-BmZZJ5ms.js +0 -1
  361. package/public/assets/SlowHost-CsJzfEqo.js +0 -1
  362. package/public/assets/SmallFiles-BoK3R1Ex.js +0 -1
  363. package/public/assets/SpeculationWaste-CnVxB5AJ.js +0 -1
  364. package/public/assets/Spill-BhNicyBy.js +0 -1
  365. package/public/assets/StageFailed-mAhHU4l_.js +0 -1
  366. package/public/assets/StageFindingGroup-BEtPWcT0.js +0 -1
  367. package/public/assets/StageHeader-DJkYkrsU.js +0 -1
  368. package/public/assets/StageShape-BDxRknLp.js +0 -1
  369. package/public/assets/StageSlowness-BPRw-otN.js +0 -1
  370. package/public/assets/Straggler-CZCbnOWP.js +0 -1
  371. package/public/assets/TaskFailures-C57YcLFQ.js +0 -1
  372. package/public/assets/TinyTask-Bi84qU7n.js +0 -1
  373. package/public/assets/UnderBroadcast-DdQV7htE.js +0 -1
  374. package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
  375. package/public/assets/finding-anchor-Cl6_5hfV.js +0 -1
  376. package/public/assets/impact-sort-CssZ6MT2.js +0 -1
  377. package/public/assets/index-2h_TgUAb.css +0 -2
  378. package/public/assets/index-B-03mG7K.js +0 -14
  379. package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
  380. package/public/assets/react-vendor-DEdfrRTJ.js +0 -9
  381. package/public/assets/select-CQjNhprm.js +0 -1
  382. package/public/assets/usePagedRows-Dyl6T8Ok.js +0 -1
  383. package/public/assets/useRecentFiles-XZEnLlal.js +0 -11
  384. package/public/assets/useSortMode-Dhvit8dt.js +0 -1
  385. package/public/docs/assets/chunks/@localSearchIndexroot.u_e5bQz4.js +0 -1
  386. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
  387. package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
  388. package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
  389. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.js +0 -1
  390. package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.lean.js +0 -1
  391. package/public/docs/assets/contributor-guide_architecture_detector-contract.md.wj6Et6UD.js +0 -1
  392. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
  393. package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
  394. package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.js +0 -1
  395. package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
  396. package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.js +0 -1
  397. package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.js +0 -1
  398. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
  399. package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
  400. package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
  401. package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
  402. package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
  403. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
  404. package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
  405. package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
  406. package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.js +0 -1
  407. package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.js +0 -1
  408. package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
  409. package/public/docs/assets/contributor-guide_development-setup.md.D9bu4j_c.lean.js +0 -1
  410. package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
  411. package/public/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
  412. package/public/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
  413. package/public/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
  414. package/public/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
  415. package/public/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
  416. package/public/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
  417. package/public/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
  418. package/public/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
  419. package/public/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
  420. package/public/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
  421. package/public/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
  422. package/public/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
  423. package/public/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
  424. package/public/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
  425. package/public/docs/assets/style.tmDhD3c8.css +0 -1
  426. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.js +0 -23
  427. package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.lean.js +0 -1
  428. package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
  429. package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
  430. package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
  431. package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
  432. package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
  433. package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.js +0 -1
  434. package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.lean.js +0 -1
  435. /package/public/docs/assets/{contributor-guide_architecture_board-widgets_caching-and-memory.md.8bH1HnZp.lean.js → contributor-guide_architecture_board-widgets_caching-and-memory.md.BYDo3ClR.lean.js} +0 -0
  436. /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
  437. /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
  438. /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
  439. /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
  440. /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
  441. /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
  442. /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
  443. /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
  444. /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
  445. /package/public/docs/assets/{user-guide_mcp-tools_get-run-summary.md.DpxZ4ZNp.lean.js → user-guide_mcp-tools_get-run-summary.md.EhaIsele.lean.js} +0 -0
@@ -60,11 +60,9 @@ export const METRIC_ANCHORS = {
60
60
  // section, and gating keeps that from becoming a dead "Learn more" link. docs-config.test.js
61
61
  // asserts this stays a subset of the real ids so it can't drift.
62
62
  export const KNOWN_DOC_ANCHORS = new Set([
63
- // Page sections
64
63
  '#intro', '#spark-architecture', '#memory-model', '#partitioning', '#joins',
65
64
  '#shuffle', '#data-formats', '#table-formats', '#caching', '#pyspark', '#aqe',
66
65
  '#cluster-config', '#anti-patterns', '#metrics', '#config',
67
- // Bottleneck sections
68
66
  '#bottleneck-cold-start', '#bottleneck-failures', '#bottleneck-gc',
69
67
  '#bottleneck-job-failure-rate', '#bottleneck-retry-waste', '#bottleneck-shuffle',
70
68
  '#bottleneck-skew', '#bottleneck-slow-host', '#bottleneck-spill',
@@ -75,10 +73,8 @@ export const KNOWN_DOC_ANCHORS = new Set([
75
73
  '#bottleneck-partition-sizing', '#bottleneck-speculation-waste',
76
74
  '#bottleneck-core-locality', '#bottleneck-caching-opportunity',
77
75
  '#bottleneck-autoscaling-churn', '#bottleneck-cache-utilization',
78
- // Config-audit sections
79
76
  '#config-autoscale-bounds', '#config-memory-overhead', '#config-serializer',
80
77
  '#config-shuffle-service',
81
- // Metric glossary entries
82
78
  ...Object.values(METRIC_ANCHORS),
83
79
  ]);
84
80
 
@@ -5,4 +5,5 @@ join/union result recomputed by two or more executions, matched by plan
5
5
  shape) may be worth persisting between stages. Self-flags a confidence that scales with
6
6
  how many executions reuse the same relation: reuse is only inferred, from
7
7
  plan-scan identity across SQL executions, so confirm the reads really do
8
- hit the same data before you cache anything.
8
+ hit the same data before you cache anything. The figure is the input those
9
+ queries scanned and how many queries scanned it, not a time.
@@ -1,16 +1,24 @@
1
1
  ### `CFG`: Configuration audit {#cfg}
2
2
 
3
3
  Flags configuration settings that may cause reliability or efficiency
4
- problems, independent of any one stage's behavior. Four checks run:
4
+ problems, independent of any one stage's behavior. Three checks run:
5
5
 
6
- - `spark.shuffle.service.enabled`: flagged when dynamic allocation is on
7
- but the external shuffle service is off, since shuffle data won't survive
8
- executor removal.
9
- - `spark.dynamicAllocation.minExecutors`/`maxExecutors`: with dynamic
10
- allocation on, flagged when min exceeds max (reported on `minExecutors`)
11
- or when no max is set.
6
+ - `spark.dynamicAllocation.maxExecutors`: with dynamic allocation on,
7
+ flagged when the effective max is Spark's unbounded default, so the cluster
8
+ can grow without a cap.
12
9
  - `spark.serializer`: flagged when not set to Kryo (the default is the Java
13
- serializer); `org.apache.spark.serializer.KryoSerializer` is faster and
14
- produces smaller buffers.
15
- - `spark.executor.memoryOverhead`: flagged when set below max(384 MiB, 10%
16
- of executor memory).
10
+ serializer), and only on a run with stages outside any SQL execution.
11
+ DataFrame and SQL shuffles and caches use Spark's own row format, so the
12
+ serializer only matters for RDD work.
13
+ `org.apache.spark.serializer.KryoSerializer` is faster and produces smaller
14
+ buffers.
15
+ - `spark.executor.memoryOverhead`: flagged when set below the overhead Spark
16
+ computes by default, max(`spark.executor.minMemoryOverhead`, executor memory
17
+ times `spark.executor.memoryOverheadFactor`). The minimum is 384 MiB and the
18
+ factor 10% unless the run sets them; each setting counts only on a Spark
19
+ version that reads it (the factor from 3.3, the minimum from 4.0).
20
+
21
+ Two settings are never flagged because Spark rejects them at startup, so no
22
+ event log carries them: dynamic allocation with neither the external shuffle
23
+ service, shuffle tracking, shuffle-block decommissioning nor a reliable
24
+ shuffle storage plugin, and `minExecutors` above `maxExecutors`.
@@ -4,4 +4,5 @@ The first stage waited more than 30 s for an executor. Keep a warm pool of
4
4
  executors, or, with dynamic allocation, raise
5
5
  `spark.dynamicAllocation.minExecutors`/`initialExecutors` so the app doesn't
6
6
  scale up from zero. With dynamic allocation off (`evidence.dynamicAllocation`
7
- is `off`) no executor-count property applies and `remediation` is empty.
7
+ is `off`, which includes a run that never set it, as Spark defaults it off) no
8
+ executor-count property applies and `remediation` is empty.
@@ -2,6 +2,10 @@
2
2
 
3
3
  Tasks spend more than 10% of executor run time reclaiming memory. Reduce
4
4
  object creation: use primitive types, avoid UDFs, or raise executor memory.
5
- A stage with GC below 5% gets an informational note that executor memory
6
- may be over-provisioned, only on stages that take at least 0.5% of the run.
7
- Both need at least 10 s of executor run time on the stage.
5
+ When the log carries no measured executor heap peaks, or the executor memory
6
+ is unknown, so [`MEM`](#mem) cannot judge the heap, a stage with GC below 5%
7
+ gets an informational note that executor memory may be over-provisioned, only
8
+ on stages that take at least 0.5% of the run, and never on a stage that failed
9
+ or lost tasks. Both need at least 10 s of executor run time on the stage. A
10
+ stage with advice to raise executor memory (high GC, volume spill, a GC-bound
11
+ straggler tail) gets no advice to lower it.
@@ -4,4 +4,14 @@ One executor is much slower than its peers, or carries most of the stage's
4
4
  task time or bytes. It may just hold data locality
5
5
  for its tasks or carry one heavy stage, rather than a hardware fault.
6
6
  Enable `spark.speculation` to relaunch a lagging task automatically. Only
7
- flagged on stages that take at least 0.5% of the run.
7
+ flagged on stages that take at least 0.5% of the run. A task-time grade
8
+ rests on the largest of N executor means, which a larger executor count reaches
9
+ by chance more often, so the finding states `confidence: low` with the executor
10
+ count and the task count.
11
+
12
+ An executor whose tasks ran slower than the median executor's is flagged only
13
+ when the gap is larger than the stage's own spread of task times and the
14
+ executor's task count allow. The slowest of 75 executors tops the median by
15
+ chance far more often than the slowest of 3, so the gap it needs grows with
16
+ the number of executors. A stage whose per-task timings are missing flags no
17
+ executor on task time.
@@ -1,13 +1,24 @@
1
1
  ### `MEM`: Memory utilization {#mem}
2
2
 
3
3
  Executor memory or core capacity may be over- or under-provisioned: more
4
- than 50% of available core time ran no task, an executor's heap peaked above
5
- 95% of its allocation, or it stayed below 70%. Some
6
- detail here needs `spark.eventLog.logStageExecutorMetrics=true` on the run
7
- being analyzed; without it, per-executor memory usage can't be broken down.
4
+ than 50% of allocated core time ran no task, or the busiest executor's heap
5
+ peak stayed below 70% of `spark.executor.memory`. Heap peaks come from the
6
+ executor metrics Spark 3+ writes on every task end (and from stage executor
7
+ metrics when `spark.eventLog.logStageExecutorMetrics=true`). Spark samples them
8
+ at executor heartbeat, so a peak is a lower bound, and the heap-used metric
9
+ counts uncollected garbage, so a peak near the limit is not reported as a
10
+ memory risk. A log with no peaks (every task ended between two heartbeats, so
11
+ each reports zeros, as in local mode) gets a note that executor memory sizing was
12
+ not measured; it suggests `spark.eventLog.logStageExecutorMetrics=true` while that
13
+ is off. A run-level finding that advises lowering executor memory (a heap under
14
+ 70%, idle allocated memory-time) keeps its figures but not that advice when any
15
+ stage asks for more memory, and names those stages; a stage's low-GC note is
16
+ dropped on a stage that asks for more. The
17
+ idle-memory figure counts the executors' alive time, not the peak executor count
18
+ over the whole run.
8
19
  Review `spark.executor.memory` and executor count if allocated memory sat
9
20
  largely idle over the run. That idle-memory variant self-flags a confidence
10
21
  that scales with how far the estimated waste sits past a 1.5x buffer: it
11
- estimates waste from allocated memory-time versus task run time (not
12
- measured heap usage). Check it against
22
+ estimates waste from allocated memory-time versus task run time per
23
+ executor core (not measured heap usage). Check it against
13
24
  the Spark UI before resizing anything.
@@ -2,4 +2,6 @@
2
2
 
3
3
  Shuffle partitions are too large, too uneven, or too few for the work. A
4
4
  single shuffle partition over 5 GB, for example, will OOM or spill heavily:
5
- repartition to break it up before the stage runs.
5
+ repartition to break it up before the stage runs. The partition-skew rule
6
+ words its advice the same way a `SKEW` finding does, including
7
+ `evidence.aqeSkew`.
@@ -1,6 +1,6 @@
1
1
  ### `PLAN`: Plan advisor {#plan}
2
2
 
3
- Flags patterns in the SQL execution plan worth reviewing. Four checks share
3
+ Flags patterns in the SQL execution plan worth reviewing. Six checks share
4
4
  this tag:
5
5
 
6
6
  - Duplicate plan subtree: the same subtree recomputed more than once in the
@@ -9,16 +9,58 @@ this tag:
9
9
  when the repeat's stages take at least 0.5% of the run.
10
10
  - Small files: one plan node reads or writes more than 100 files averaging
11
11
  under 3 MB. Compact upstream output, or coalesce before writing.
12
- - Under-broadcast: the smaller side of a Sort Merge Join looks well under
13
- the broadcast threshold; consider a `broadcast()` hint or raising
14
- `spark.sql.autoBroadcastJoinThreshold`. When the effective threshold
15
- (logged, else Spark's 10 MiB) already admits the smaller side
16
- (`evidence.broadcastThreshold` is `notLimiting`), the threshold is not what
17
- stopped the broadcast, so `remediation` is empty and the advice is a hint or
18
- table statistics.
12
+ - Nested loop join: a `BroadcastNestedLoopJoin` or `CartesianProduct` whose
13
+ output has at least 1,000,000 rows (the rows a `CartesianProduct`'s condition
14
+ kept, when it has one). A `BroadcastNestedLoopJoin` must also
15
+ produce at least 10 times the rows of its larger input; a `CartesianProduct`
16
+ is judged on its output alone, because it re-reads each input once per
17
+ partition of the other side, so the input row counts the executors report
18
+ are not row counts. Spark plans these when a join has no equi-join key. The
19
+ finding carries the join condition and is graded by the time of the stages
20
+ that run the join. The advice is to add an equi-join key, to bucket the range
21
+ of a range join and join on the bucket, or to confirm that a cross join is
22
+ intended. It needs the executors' `number of output rows` metrics, so a join
23
+ with no reported row counts is not flagged.
24
+ - Row-at-a-time Python UDF: a plan runs `BatchEvalPython`, which pickles
25
+ every row to a Python worker and back. Flagged when its stages sent at
26
+ least 64 MiB to the workers (`data sent to Python workers`) and ran for at
27
+ least 30 seconds together; the finding reports the bytes sent and returned
28
+ and the stage time, and is informational. `ArrowEvalPython` (Arrow-optimized
29
+ and pandas UDFs) is never flagged. The advice is
30
+ `spark.sql.execution.pythonUDF.arrow.enabled=true` (Spark 3.4 and later;
31
+ already the default from 4.2, where the UDF may have opted out with
32
+ `useArrow=False`, take no arguments, or have been created before the property
33
+ was set) or a pandas UDF. These floors are conservative guesses,
34
+ not tuned against real workloads. A plan that reports no
35
+ `data sent to Python workers` value is skipped.
36
+ - Under-broadcast: a side of a Sort Merge Join that its join type can
37
+ broadcast (`evidence.buildSide`, sized by the finding's value) was not
38
+ broadcast although it is small enough: it is over a small effective
39
+ threshold (`evidence.broadcastThreshold` is `limits`), or automatic
40
+ broadcast is disabled with `-1` (`disabled`); consider a `broadcast()` hint
41
+ or setting the threshold property. The size is
42
+ the shuffle's `data size`, the metric adaptive execution compares at runtime.
43
+ The threshold is `spark.sql.adaptive.autoBroadcastJoinThreshold` when the
44
+ plan is adaptive and that property is set, else
45
+ `spark.sql.autoBroadcastJoinThreshold` (the query's own setting, else the
46
+ logged one, else Spark's 10 MiB). A full outer join never fires, and a side
47
+ under 1 MiB or over the over-broadcast limit is skipped. When the effective
48
+ threshold already admits the side (`evidence.broadcastThreshold` is
49
+ `notLimiting`), the threshold is not what stopped the broadcast, so
50
+ `remediation` is empty and the advice is a hint or table statistics (for an
51
+ adaptive plan, `spark.sql.adaptive.nonEmptyPartitionRatioForBroadcastJoin`:
52
+ AQE keeps a side with a low share of non-empty partitions out of a broadcast
53
+ whatever its size). Both
54
+ sides need a shuffle `data size` of their own, so a join over another join's
55
+ output is skipped, and so is a join whose only buildable side is larger than
56
+ the other side, since broadcasting it saves nothing. The build side is
57
+ always the smaller one and `evidence.largerSideBytes` is the other side.
19
58
  - Over-broadcast: a broadcast exceeds the 1 GB threshold; check for a
20
- misapplied broadcast hint or a misconfigured
21
- `spark.sql.autoBroadcastJoinThreshold`. When the effective threshold is
22
- below the broadcast or auto-broadcast is disabled (`evidence.broadcastThreshold`
23
- is `notLimiting` or `disabled`), a hint forced it: remove the hint, and
24
- `remediation` is empty.
59
+ misapplied broadcast hint or a misconfigured threshold property. Under
60
+ adaptive execution a broadcast planned up front is admitted by
61
+ `spark.sql.autoBroadcastJoinThreshold` and one converted at runtime by
62
+ `spark.sql.adaptive.autoBroadcastJoinThreshold` (when set), so the finding
63
+ names whichever of them admits the broadcast. When every applicable
64
+ threshold is below the broadcast or disabled (`evidence.broadcastThreshold`
65
+ is `notLimiting`, or `disabled` when all are disabled), a hint forced it:
66
+ remove the hint, and `remediation` is empty.
@@ -4,8 +4,14 @@ Tasks move a large amount of intermediate data between stages. Raise
4
4
  `spark.sql.shuffle.partitions`, or add a broadcast join. The partition-count
5
5
  advice follows the effective conf (`evidence.partitions`): `raise` when the
6
6
  property limits the stage, `sufficient` when the tasks already read a good
7
- size each, `aqeCoalesced` when AQE merged the partitions (lower
8
- `spark.sql.adaptive.advisoryPartitionSizeInBytes`), and `ownPartitioning` when
9
- the property is already high enough (the stage's own `repartition(n)` or RDD
10
- parallelism limits it). Only flagged on stages that take at least 0.5% of the
11
- run.
7
+ size each, `aqeCoalesced` when AQE merged the partitions of a stage in a SQL
8
+ execution (lower `spark.sql.adaptive.advisoryPartitionSizeInBytes`), and
9
+ `ownPartitioning` when the property is already high enough (the stage's own
10
+ `repartition(n)` or RDD parallelism limits it, as for any stage outside a SQL
11
+ execution). With AQE coalescing on,
12
+ `spark.sql.adaptive.coalescePartitions.initialPartitionNum` replaces the
13
+ property as the starting count when it is set, and a stage that ran more tasks
14
+ than that, with a skew split in the final plan or no final plan to rule one
15
+ out, is not blamed on its own `repartition(n)`: the advice states the task and
16
+ configured counts and names `repartition(n)` only when the plan holds one the
17
+ job wrote. Only flagged on stages that take at least 0.5% of the run.
@@ -8,7 +8,54 @@ stage. The fix depends on what the stage reads, which the finding's
8
8
  already has it; otherwise salt the key or repartition on a better key. A
9
9
  stage that reads files with uneven sizes (`inputScan`) gets compaction of
10
10
  small files or a lower `spark.sql.files.maxPartitionBytes`. Any other stage
11
- (`other`) gets the salting advice and no conf. Flagged when P95 task time
11
+ (`other`) gets the salting advice and no conf, as a `code` entry in
12
+ `remediation`. Flagged when P95 task time
12
13
  (the longest task, on a stage with fewer than 20 tasks) exceeds 3x the median
13
14
  and the recoverable tail is at least 0.5% of the run. The median is the
14
15
  textbook one: on an even task count, the mean of the two middle values.
16
+
17
+ Skew is a statement about data volume, as in Spark's UI and AQE. Each stage's
18
+ slow tasks (over 3x the median task) are compared with the median task's input
19
+ plus shuffle-read bytes and records. If run time scaled with that volume, the
20
+ share of the slow tasks' extra time it accounts for is the data share; at 50% or
21
+ more the tail is skew (`evidence.cause` is `data`, `evidence.dataRatio` is the
22
+ median slow task's volume over the median task's). A tail that mostly is not data
23
+ is reported as `STRAG` with its cause. Ratios are taken only against a median task that read at least
24
+ 1 MiB or 1,000 records, so a median of a few bytes never prints a huge multiple. When the median task read less than that floor (almost nothing),
25
+ there is no ratio to take (`evidence.dataRatio` is absent, and the advice says the
26
+ median task read almost nothing): GC and fetch wait claim their share of the slow
27
+ tasks' extra time first, and a slow task that read data (at least 1 MiB or 1,000
28
+ records) owns what is left. When the data share is under 50%, the cause is the largest
29
+ of GC, fetch wait, host and what none of them accounts for. With no data volume
30
+ to compare, what none of them accounts for is labelled `unattributed` (no share is
31
+ reported) instead of `unexplained`; GC, fetch wait or host still win when larger. A
32
+ stage with no tail attribution is `unattributed` too. An `unattributed` tail is
33
+ reported as `STRAG` only, never as `SKEW`.
34
+
35
+ With AQE skew-join handling on, a `shuffleJoin` stage's advice says why
36
+ handling did or did not act on that stage's join, read from the execution's
37
+ final plan and its effective conf. `evidence.aqeSkew` records the case:
38
+
39
+ | `aqeSkew` | What the final plan and conf show | Advice |
40
+ |---|---|---|
41
+ | `split` | The join is marked `skew=true` and a shuffle read says `skewed` | AQE already split the skewed partitions, so what remains is not join skew: look at GC, a slow host or an expensive key. When the tail is data (`evidence.cause` is `data`), the slow tasks still read far more data than the median task, and the advice is the key remedy. |
42
+ | `evenReads` | One join side shuffles next to nothing, so the task read is the other side's, and the largest task read is under twice the median | The slow tail is not partition-size skew: look at GC, a slow host or an expensive key. Never given when `evidence.cause` is `data`, which counts input and records as well as shuffle-read bytes. |
43
+ | `belowThreshold` | The largest task read is under `spark.sql.adaptive.skewJoin.skewedPartitionThresholdInBytes` (256 MB by default), which bounds every partition of both sides; or one side's read is at least twice the median but not far enough over it for `spark.sql.adaptive.skewJoin.skewedPartitionFactor` (5) | Lower the threshold or the factor for the query. |
44
+ | `planShape` | An aggregate, window or other operator sits between the join and its shuffle | AQE splits only a shuffle that feeds the join directly: salt the key. |
45
+ | `userRepartition` | The shuffle under the join is a `repartition` or `rebalance` in the job's code | AQE leaves a shuffle you asked for alone: drop it, or salt the key. |
46
+ | `joinType` | The join type does not let AQE split the skewed side: neither side of a full outer join, only the left side of a left outer, left semi or left anti join, only the right side of a right outer join | Join the hot key on its own and union the results, or salt the key. Swapping the sides does not help: the null-supplying or filtering table stays unsplittable. |
47
+ | `extraShuffle` | An aggregate, window or join above this join needs its partitioning, so a split would add a shuffle | Set `spark.sql.adaptive.forceOptimizeSkewedJoin` to `true` when that shuffle costs less than the tail (Spark 3.3 and later; before that, salt the key). |
48
+ | `notSplit` | Nothing above explains it | Salt the key. |
49
+
50
+ The stage's join is the one whose plan node ran in that stage; a plan whose
51
+ nodes carry no stage ids is read as one join only when the stage's shuffle read
52
+ matches what the join's two shuffles wrote. A task reads one partition of each
53
+ join side, so the stage's largest task read covers both sides. Spark judges each
54
+ side's partitions against that side's own median, which the log does not give, so
55
+ the finding calls the reads even or under the factor only when one side shuffles
56
+ at most 5% of the join's bytes; otherwise it can only show a partition is under
57
+ the absolute threshold (a task's read bounds every partition in it). The finding
58
+ does not say which side is skewed; for a join type that splits only one side it
59
+ names both possibilities. A run whose final plan is missing or ties no join to
60
+ the stage, or whose coalesced read could be many small partitions, keeps the
61
+ general advice.
@@ -2,8 +2,10 @@
2
2
 
3
3
  A stage ran for 15 minutes or more and no slow host was flagged on it. It
4
4
  can appear alongside other findings on the same stage. On a stage that reads a
5
- shuffle, often a partition-count problem: raise parallelism via
6
- `spark.sql.shuffle.partitions` or `spark.default.parallelism`, or check for a
5
+ shuffle, often a partition-count problem: raise `spark.sql.shuffle.partitions`
6
+ when the stage ran that many tasks, lower
7
+ `spark.sql.adaptive.advisoryPartitionSizeInBytes` when AQE coalesced them, or
8
+ raise the stage's own `repartition(n)` or RDD parallelism; or check for a
7
9
  large per-task data volume driving heavy shuffle and spill. On a stage that
8
10
  reads input files and no shuffle, check input file sizes and lower
9
11
  `spark.sql.files.maxPartitionBytes`. `evidence.reads` says which case
@@ -4,4 +4,9 @@ Speculative task attempts used a lot of executor time without confirming a
4
4
  genuine straggler. Self-flags a confidence that scales with how far the
5
5
  wasted time sits past the threshold. If task durations are just naturally
6
6
  variable rather than genuine stragglers, tune
7
- `spark.speculation.multiplier`/`spark.speculation.quantile`.
7
+ `spark.speculation.multiplier`/`spark.speculation.quantile`. The
8
+ recommendation names the run's effective values: Spark relaunches a task that
9
+ runs over the multiplier times the median once the quantile of the stage's
10
+ tasks has finished, which is 1.5x and 75% before Spark 4.0 and 3x and 90% from
11
+ 4.0 unless the job sets them. A speculative-attempt `straggler` and a
12
+ `slowHost` finding word their speculation advice the same way.
@@ -4,7 +4,10 @@ Tasks are writing data out of memory, which slows execution. Two spill
4
4
  patterns get flagged differently: skew spill, where a few heavy tasks spill
5
5
  while most don't (rebalance partitioning), and volume spill, where most
6
6
  tasks spill because the data genuinely exceeds available memory (add
7
- partitions or executor memory). `spark.sql.shuffle.partitions` is suggested
8
- only for a stage that reads a shuffle; `evidence.reads` says what the stage
9
- reads (`shuffle`, `input` or `other`). Only flagged on stages that take at
7
+ partitions or executor memory). Partition-count advice is given only for a
8
+ stage that reads a shuffle; `evidence.reads` says what the stage reads
9
+ (`shuffle`, `input` or `other`). It names what sized the stage:
10
+ `spark.sql.shuffle.partitions` when the stage ran that many tasks,
11
+ `spark.sql.adaptive.advisoryPartitionSizeInBytes` when AQE coalesced them, and
12
+ the stage's own `repartition(n)` or RDD parallelism otherwise. Only flagged on stages that take at
10
13
  least 0.5% of the run.
@@ -1,8 +1,21 @@
1
1
  ### `STRAG`: Straggler tasks {#strag}
2
2
 
3
- A few tasks run much slower than the rest of their stage. Rule out a GC
4
- pause or a slow shuffle fetch before assuming a hardware issue. If uneven
5
- data is the cause, the advice is the one a skew finding gives for the same
6
- stage (`evidence.origin`, see `SKEW`): AQE skew-join handling for a shuffle
7
- feeding a join, file sizes for a scan, salting otherwise. Only flagged on
8
- stages that take at least 0.5% of the run.
3
+ A few tasks run much slower than the rest of their stage for a reason other
4
+ than reading more data (a data-driven tail is `SKEW`). `evidence.cause` names
5
+ what the slow tasks' extra time went to, taken in this order so no millisecond
6
+ counts twice: data volume, then GC time over the median task's, then shuffle
7
+ fetch wait over the median task's, then one host that holds most of the slow
8
+ tasks out of proportion to its share of the stage (`evidence.host`). What none of
9
+ them accounts for is `unexplained` (`unattributed` with no data volume to compare); an
10
+ `unexplained` tail whose slow tasks read at least twice the median task's data says so
11
+ rather than "no more data", and keeps the `SKEW` data advice when data is its largest share; `evidence.cpuPct` (the slow tasks' CPU time
12
+ over their run time) says whether those tasks mostly waited or were busy. With
13
+ no data volume to compare, what is left is `unattributed` when it is the largest share, as is a stage
14
+ with no tail attribution: the advice names no fix, only the slow tasks' input sizes, GC time and hosts to check.
15
+ A stage is flagged when more than 5% of its tasks run over 4x the median (2.5%
16
+ when the tail clears 0.5% of the run), a speculative task ran, or the `SKEW`
17
+ duration test holds on a tail that is not data. A stage whose tail is data but
18
+ which `SKEW` does not flag by duration keeps a `STRAG` finding with cause `data`. A finding only the `SKEW` duration
19
+ test admits reports that test's ratio (`metric` `P95/median` or `max/median`, `unit` `ratio`)
20
+ instead of a share.
21
+ Stages under 0.5% of the run are skipped unless the `SKEW` duration test holds.
@@ -1,6 +1,12 @@
1
1
  ### `TINY`: Tiny tasks {#tiny}
2
2
 
3
3
  Many very short tasks add scheduling overhead out of proportion to the work
4
- each one does. Repartition to fewer, larger tasks; a stage that reads a shuffle
5
- (`evidence.reads` is `shuffle`) can also lower `spark.sql.shuffle.partitions`.
6
- Only flagged on stages that take at least 0.5% of the run.
4
+ each one does. Repartition to fewer, larger tasks. On a stage that reads a
5
+ shuffle (`evidence.reads` is `shuffle`) the advice names what sized it: lower
6
+ `spark.sql.shuffle.partitions` when the stage ran that many tasks; when AQE
7
+ coalesced them and still kept tiny ones, set
8
+ `spark.sql.adaptive.coalescePartitions.parallelismFirst` to `false` (AQE then
9
+ targets `spark.sql.adaptive.advisoryPartitionSizeInBytes` rather than
10
+ `defaultParallelism` tasks) and then raise the advisory size, which alone changes
11
+ nothing while `parallelismFirst` is on; otherwise lower the
12
+ `repartition(n)` or RDD partition count in the code. Only flagged on stages that take at least 0.5% of the run.
@@ -1,4 +1,8 @@
1
1
  ### `UTIL`: Low utilization {#util}
2
2
 
3
- Allocated executors sit idle for a large share of the application run.
4
- Consider a smaller cluster, or enable dynamic allocation.
3
+ Allocated executors sit idle for a large share of the application run: under
4
+ 60% of the core time the run allocated (cores times the time each executor was
5
+ alive) ran a task. Consider a smaller cluster. With dynamic allocation off,
6
+ either lower `spark.executor.instances` or enable dynamic allocation; the two are
7
+ alternatives. With it on, lower `spark.dynamicAllocation.maxExecutors`, and
8
+ `spark.dynamicAllocation.minExecutors` too when the run sets it above 0.
@@ -1,8 +1,7 @@
1
1
  // The effective Spark configuration of a run for the CLI's JSON output, so a caller can check
2
- // that a --conf overlay took effect. Every key is listed; a value is withheld when the key or the
3
- // value matches a secret pattern, and credentials inside URL-like values are stripped. A withheld
4
- // key is shown as present with no value, and no derivative of the value (no hash, length or
5
- // prefix) is emitted.
2
+ // that a --conf overlay took effect. A withheld key is shown as present with no value, and no
3
+ // derivative of the value (no hash, length or prefix) is emitted. Patterns and output shape:
4
+ // docs-site/user-guide/getting-started/ci-and-automation.md, "Effective conf".
6
5
 
7
6
 
8
7
  export const EFFECTIVE_CONF_SCHEMA_VERSION = 1;
@@ -50,16 +49,14 @@ export function compileJvmPattern(source ) {
50
49
  // Sensitive query/parameter names in a URL-like value: signatures of pre-signed and SAS URLs.
51
50
  const SIGNATURE_PARAMS = 'sig|signature|x-amz-signature|x-amz-credential|x-amz-security-token|x-goog-signature|x-goog-credential';
52
51
 
53
- // A `name=value` credential parameter in any value (a JDBC or ODBC string, a JVM option, a query
54
- // string): `password`, `pwd`, `pass`, `apikey`, `accountkey`, `sas`, `sig` and the like, alone or as
55
- // the tail of a longer name (`-Djavax.net.ssl.keyStorePassword=`).
52
+ // A `name=value` credential parameter in any value (JDBC or ODBC string, JVM option, query string),
53
+ // alone or as the tail of a longer name (`-Djavax.net.ssl.keyStorePassword=`).
56
54
  const CREDENTIAL_PARAM = new RegExp(
57
55
  '((?:^|[\\s;&,?:"\'(]|-D)(?:[\\w.-]*?(?:password|passwd|pwd|secret|token|api[_.-]?key|account[_.-]?key|access[_.-]?key|private[_.-]?key)|pass|sas|credential|'
58
56
  + `${SIGNATURE_PARAMS})\\s*=\\s*)("[^"]*"|'[^']*'|[^;&,\\s"']*)`, 'gi');
59
57
 
60
- /** Strips credentials from a value: `name=value` credential parameters anywhere (JDBC
61
- * `password=`/`pwd=`/`pass=`, `apiKey=`, signature parameters such as Azure SAS `sig=`), and, in a
62
- * value that looks like a URL, userinfo (user:password@host) and the Oracle thin form
58
+ /** Strips credentials from a value: `name=value` credential parameters anywhere, and, in a value
59
+ * that looks like a URL, userinfo (user:password@host) and the Oracle thin form
63
60
  * (jdbc:oracle:thin:user/password@host). */
64
61
  export function stripUrlCredentials(value ) {
65
62
  const urlLike = /^[a-z][a-z0-9+.-]*:/i.test(value) || value.includes('://');
@@ -1,12 +1,13 @@
1
- // §5 Efficiency/wastage model. DESIGN SPIKE:
2
- // decomposes available compute-hours into driver-bound vs executor-bound waste, plus two floors.
3
- import { computeWallClock } from './wall-clock.js';
1
+ // Efficiency/wastage model: decomposes available compute-hours into driver-bound vs executor-bound
2
+ // waste, plus the zero-skew makespan floor.
3
+ import { stageWindows } from './wall-clock.js';
4
+ import { allocatedCoreMs, allocatedCoreMsWithin } from './allocation.js';
4
5
  import { computePeakConcurrentCores } from './core-count.js';
5
6
 
6
7
 
7
8
  export function computeEfficiencyModel({ app, stages, executorsAdded, executorsRemoved, runAggregates }
8
9
 
9
-
10
+
10
11
 
11
12
 
12
13
 
@@ -18,23 +19,25 @@ export function computeEfficiencyModel({ app, stages, executorsAdded, executorsR
18
19
 
19
20
 
20
21
  {
21
- // Capacity is the peak concurrent core count, the one the utilization and idle-cores detectors
22
- // use, so the Unused core time tile matches the verdict's idle figure. Summing every addition
23
- // (computeTotalCores) counts a replaced executor's cores alongside its replacement's.
24
- // `app ?? {}`: callers tolerate a null app (malformed logs); `app!` would crash on app.resources.
25
- const totalCores = computePeakConcurrentCores(app ?? {}, executorsAdded, executorsRemoved);
26
- const appDurationMs = (app?.endTime ?? 0) - (app?.startTime ?? 0);
27
- const wc = computeWallClock(app, stages );
22
+ // Capacity is the run's allocation (cores x time alive, metrics.allocation.coreHours), the one the
23
+ // utilization and idle-cores detectors use, so the Unused core time tile matches the verdict's
24
+ // idle figure. Peak concurrent cores times the whole run would count cores the run never held
25
+ // under dynamic allocation. Null without executor cores: no capacity, so no figure.
26
+ const input = { app, stages, executors: { added: executorsAdded, removed: executorsRemoved } };
27
+ const allocatedMs = allocatedCoreMs(input);
28
+ // Split by where the allocated cores were held, from the same alive intervals: inside the union
29
+ // of the stages' windows, or outside it (startup, gaps between stages, after the last stage).
30
+ // Executors that join after startup hold no cores there, so spreading the allocation evenly
31
+ // over the run would bill the driver for cores that never existed.
32
+ const allocatedActiveCoreMs = allocatedMs == null ? 0 : allocatedCoreMsWithin(input, stageWindows(stages)) ?? 0;
28
33
 
29
- const availableComputeHours = totalCores * (appDurationMs / 3600000);
34
+ const availableComputeHours = (allocatedMs ?? 0) / 3600000;
30
35
 
31
- // Driver-bound: cores idle during startup + gaps + idle (no active stage).
32
- const driverIdleMs = wc.startup + wc.gaps + wc.idle;
33
- const driverWasteHours = totalCores * (driverIdleMs / 3600000);
36
+ // Driver-bound: cores held while no stage was active (startup, gaps, idle).
37
+ const driverWasteHours = Math.max(0, (allocatedMs ?? 0) - allocatedActiveCoreMs) / 3600000;
34
38
 
35
39
  // Executor-bound: allocated capacity beyond busy cores during stagesActive. Tasks only run in
36
40
  // active windows, so whole-run busyCoreMs already lives inside stagesActive.
37
- const allocatedActiveCoreMs = totalCores * wc.stagesActive;
38
41
  const busyCoreMs = runAggregates?.busyCoreMs ?? 0;
39
42
  const executorWasteHours = Math.max(0, allocatedActiveCoreMs - busyCoreMs) / 3600000;
40
43
 
@@ -44,6 +47,11 @@ export function computeEfficiencyModel({ app, stages, executorsAdded, executorsR
44
47
  let totalTaskMs = 0;
45
48
  const perStage = runAggregates?.perStage ?? {};
46
49
  for (const k of Object.keys(perStage)) totalTaskMs += perStage[k].totalTaskDurationSum;
50
+ // The floor is the least time the work takes on the widest the cluster ever was: peak concurrent
51
+ // cores (not the allocation), summing every addition (computeTotalCores) would count a replaced
52
+ // executor's cores alongside its replacement's. `app ?? {}`: callers tolerate a null app
53
+ // (malformed logs); `app!` would crash on app.resources.
54
+ const totalCores = computePeakConcurrentCores(app ?? {}, executorsAdded, executorsRemoved);
47
55
  const floorZeroSkewMs = totalCores > 0 ? totalTaskMs / totalCores : 0;
48
56
 
49
57
  let dominantWaste = null;
@@ -1,5 +1,4 @@
1
- // §7 ETL-phase time attribution (Onehouse Spark Analyzer). Heuristic: classify each stage by
2
- // byte-flow shape. A stage can be both Transform and Load, so buckets overlap and need not sum to
1
+ // ETL-phase time attribution. Heuristic: classify each stage by byte-flow shape. A stage can be both Transform and Load, so buckets overlap and need not sum to
3
2
  // wall-clock. Storage-format-aware attribution (Hudi/Delta/Iceberg) isn't portable, out of scope.
4
3
 
5
4