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.
- package/index.js +16 -7
- package/package.json +1 -1
- package/public/assets/AutoscalingChurn-DenWKTv-.js +1 -0
- package/public/assets/CacheUtilization-DLz7NdjV.js +1 -0
- package/public/assets/CachingOpportunity-zpQIqhzm.js +1 -0
- package/public/assets/ChartTheme-DAiARbLP.js +8 -0
- package/public/assets/ColdStart-C-9HjxWl.js +1 -0
- package/public/assets/ConfigAudit-D0V9tcrJ.js +1 -0
- package/public/assets/CoreUsageArea-yeerrljd.js +1 -0
- package/public/assets/Dashboard-DkUPrHKV.js +1 -0
- package/public/assets/DisclosureContext-DK1_iz6J.js +1 -0
- package/public/assets/DuplicatePlanSubtree-xDNDbCd3.js +1 -0
- package/public/assets/DurationHistogram-B6jsE0Ov.js +1 -0
- package/public/assets/EmptyState-C1uL40VU.js +1 -0
- package/public/assets/ExecutorUtilization-DXDZKmSc.js +1 -0
- package/public/assets/GcPressure-MRf7I4IG.js +1 -0
- package/public/assets/ImpactEstimate-Dm3xWbzV.js +1 -0
- package/public/assets/IncompleteRun-CaLOhMtf.js +1 -0
- package/public/assets/JobFailures-CzmzlvhO.js +1 -0
- package/public/assets/MemoryUtilization-AWUMUjCH.js +1 -0
- package/public/assets/NestedLoopJoin-C9sNr6Ss.js +1 -0
- package/public/assets/OverBroadcast-BOmRE6ca.js +1 -0
- package/public/assets/PartitionHint-BL2EmJfE.js +1 -0
- package/public/assets/PartitionSizing-BzBySvUq.js +1 -0
- package/public/assets/PlanExplorer-DdiQRcJU.js +1 -0
- package/public/assets/PlanGraphRoute-CIH9gBuR.js +1 -0
- package/public/assets/PlanView-B1hxzFRs.js +2 -0
- package/public/assets/PythonUdf-DvgCCueD.js +1 -0
- package/public/assets/RetryWaste-uXXu_CyM.js +1 -0
- package/public/assets/RowPagination-C-LzWkI5.js +1 -0
- package/public/assets/RowStatusCluster-Dbtmte7l.js +1 -0
- package/public/assets/ShuffleIO-nALwzC1_.js +1 -0
- package/public/assets/Skew-CHMEKgvk.js +1 -0
- package/public/assets/SlowHost-yyvjpHk6.js +1 -0
- package/public/assets/SmallFiles-y6odJ97n.js +1 -0
- package/public/assets/SpeculationWaste-C-SD2LOt.js +1 -0
- package/public/assets/Spill-DHTMmOup.js +1 -0
- package/public/assets/StageFailed-CQ3DxC9R.js +1 -0
- package/public/assets/StageFindingGroup-BgYLyj5q.js +1 -0
- package/public/assets/StageHeader-CIETkjVZ.js +1 -0
- package/public/assets/StagePill--P7PDd3s.js +1 -0
- package/public/assets/StageShape-BIv8vx_o.js +1 -0
- package/public/assets/StageSlowness-MMqzERxN.js +1 -0
- package/public/assets/Straggler-BgrY7AyW.js +1 -0
- package/public/assets/TaskFailures-BHHyKYTs.js +1 -0
- package/public/assets/TinyTask-DDScNhCl.js +1 -0
- package/public/assets/UnderBroadcast-CGIC04TI.js +1 -0
- package/public/assets/WidgetLeadSummary-CXFZP00C.js +1 -0
- package/public/assets/button-DbpTz2yk.js +1 -0
- package/public/assets/charts-vendor-CtTxwTeu.js +59 -0
- package/public/assets/composite-C9Nu2EI9.js +1 -0
- package/public/assets/d3-vendor-DNlD2-cz.js +1 -0
- package/public/assets/detector-registry-Bp8hrLua.js +2 -0
- package/public/assets/downsample-WmNM1qc9.js +1 -0
- package/public/assets/finding-anchor-Dr40LkS9.js +1 -0
- package/public/assets/findings-of-type-BL2u3RGZ.js +1 -0
- package/public/assets/impact-sort-mC5ISgX8.js +1 -0
- package/public/assets/inbox-KPU1Gppm.js +1 -0
- package/public/assets/index-CaRVPvAT.css +2 -0
- package/public/assets/index-fDiwfuoO.js +14 -0
- package/public/assets/inertValue-L9VxV0VE.js +1 -0
- package/public/assets/instrument-sans-latin-ext-wdth-normal-C5E2Gvlv.woff2 +0 -0
- package/public/assets/instrument-sans-latin-wdth-normal-BVScPF0l.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-ext-wght-normal-DBQx-q_a.woff2 +0 -0
- package/public/assets/jetbrains-mono-latin-wght-normal-B9CIFXIH.woff2 +0 -0
- package/public/assets/layout.worker-CLcBHxVp.js +3 -0
- package/public/assets/{parser-worker-CA5RxqKc.js → parser-worker-CRIOPMOW.js} +8 -8
- package/public/assets/plan-graph-vendor-Ce6d4HU6.js +7 -0
- package/public/assets/react-vendor-C6KcUD36.js +9 -0
- package/public/assets/select-BHqOqun5.js +1 -0
- package/public/assets/toggle-DPeN6aNa.js +1 -0
- package/public/assets/toggle-group-Kl3uyHSr.js +1 -0
- package/public/assets/usePagedRows-BafD6bEN.js +1 -0
- package/public/assets/useRecentFiles-DzJZAoOT.js +3 -0
- package/public/assets/useRegisterFieldControl-pQv-ZDoU.js +1 -0
- package/public/assets/useScrollLock-BCxn_dMp.js +1 -0
- package/public/assets/useSortMode-DjrAN-z4.js +1 -0
- package/public/docs/404.html +3 -7
- package/public/docs/assets/{app.eYTPqTeq.js → app.1gvzd5Zb.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.DS2TQP5_.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.DsZrQKQR.js → VPLocalSearchBox.CNxT3s0I.js} +1 -1
- package/public/docs/assets/chunks/{theme.DsTNE2pE.js → theme.C5lLqUv7.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.CqKM_jEG.lean.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.ajUAVdbc.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.WqY74T0T.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.CHHgywoP.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_detector-contract.md.wj6Et6UD.lean.js → contributor-guide_architecture_detector-contract.md.CHHgywoP.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.DIz3_oz9.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.WH4tRHPL.js +1 -0
- 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
- package/public/docs/assets/{contributor-guide_architecture_drill-down.md.CqZPrdo9.js → contributor-guide_architecture_drill-down.md.yB-Hz2XT.js} +1 -1
- 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
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.BQZE04sw.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.K71YB-Rr.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.DLCAffwn.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.JFrzDMwo.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_overview.md.nxkpOhgf.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.U-9KMDFK.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.B7rjSF_h.lean.js +1 -0
- 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
- 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
- package/public/docs/assets/{contributor-guide_architecture_worker-protocol.md.BAnhi2-d.js → contributor-guide_architecture_worker-protocol.md.Br6OE7RW.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.Br6OE7RW.lean.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.IVyaXrGe.js +1 -0
- 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
- 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
- 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
- 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
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.CtmCU57I.js +1 -0
- 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
- package/public/docs/assets/contributor-guide_contributing.md.DBW4drtZ.js +1 -0
- package/public/docs/assets/{contributor-guide_development-setup.md.D9bu4j_c.js → contributor-guide_development-setup.md.B21ZTDhn.js} +3 -3
- package/public/docs/assets/contributor-guide_development-setup.md.B21ZTDhn.lean.js +1 -0
- package/public/docs/assets/contributor-guide_testing.md.DpkozNoG.js +4 -0
- package/public/docs/assets/{contributor-guide_testing.md.By6XGR9a.lean.js → contributor-guide_testing.md.DpkozNoG.lean.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.js → index.md.lMm7SUMz.js} +1 -1
- package/public/docs/assets/{index.md.CHJVslga.lean.js → index.md.lMm7SUMz.lean.js} +1 -1
- package/public/docs/assets/instrument-sans-latin-ext-wdth-normal.C5E2Gvlv.woff2 +0 -0
- package/public/docs/assets/instrument-sans-latin-wdth-normal.BVScPF0l.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-cyrillic-wght-normal.D73BlboJ.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-greek-wght-normal.Bw9x6K1M.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-latin-ext-wght-normal.DBQx-q_a.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-latin-wght-normal.B9CIFXIH.woff2 +0 -0
- package/public/docs/assets/jetbrains-mono-vietnamese-wght-normal.Bt-aOZkq.woff2 +0 -0
- package/public/docs/assets/style.Cfxqlj0y.css +1 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.js +29 -0
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.C0pcQoNc.lean.js +1 -0
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.CGaxPX_1.js +1 -0
- 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
- 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
- package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.js → user-guide_mcp-tools.md.49r3L2YE.js} +1 -1
- 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
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.BQ_kIptC.lean.js +1 -0
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.azCZXkH8.js +44 -0
- 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
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js → user-guide_mcp-tools_evaluate-budgets.md.dpQpRQ7z.js} +2 -2
- 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
- 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
- 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
- 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
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.B_LOkdBf.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C4riKCKl.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +6 -10
- package/public/docs/contributor-guide/architecture/board-widgets.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +6 -10
- package/public/docs/contributor-guide/architecture/detector-contract.html +6 -10
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +6 -10
- package/public/docs/contributor-guide/architecture/drill-down.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +6 -10
- package/public/docs/contributor-guide/architecture/impact-estimation.html +6 -10
- package/public/docs/contributor-guide/architecture/index.html +5 -9
- package/public/docs/contributor-guide/architecture/overview.html +6 -10
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +5 -9
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +6 -10
- package/public/docs/contributor-guide/architecture/state-and-history.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +5 -9
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +6 -10
- package/public/docs/contributor-guide/architecture/widget-rendering.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +7 -11
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +6 -10
- package/public/docs/contributor-guide/architecture/worker-protocol.html +6 -10
- package/public/docs/contributor-guide/contributing.html +6 -10
- package/public/docs/contributor-guide/development-setup.html +8 -12
- package/public/docs/contributor-guide/testing.html +9 -10
- package/public/docs/favicon.svg +2 -2
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +6 -10
- package/public/docs/logo-dark.svg +1 -0
- package/public/docs/logo-light.svg +1 -0
- package/public/docs/tuning-reference/anti-patterns.html +5 -9
- package/public/docs/tuning-reference/aqe.html +5 -9
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +5 -9
- package/public/docs/tuning-reference/bottleneck-cold-start.html +5 -9
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +5 -9
- package/public/docs/tuning-reference/bottleneck-failures.html +5 -9
- package/public/docs/tuning-reference/bottleneck-gc.html +5 -9
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +5 -9
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +5 -9
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +5 -9
- package/public/docs/tuning-reference/bottleneck-shuffle.html +5 -9
- package/public/docs/tuning-reference/bottleneck-skew.html +5 -9
- package/public/docs/tuning-reference/bottleneck-slow-host.html +5 -9
- package/public/docs/tuning-reference/bottleneck-small-files.html +5 -9
- package/public/docs/tuning-reference/bottleneck-spill.html +5 -9
- package/public/docs/tuning-reference/bottleneck-straggler.html +5 -9
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +5 -9
- package/public/docs/tuning-reference/bottleneck-utilization.html +5 -9
- package/public/docs/tuning-reference/caching.html +5 -9
- package/public/docs/tuning-reference/cluster-config.html +5 -9
- package/public/docs/tuning-reference/config.html +5 -9
- package/public/docs/tuning-reference/data-formats.html +5 -9
- package/public/docs/tuning-reference/index.html +5 -9
- package/public/docs/tuning-reference/intro.html +5 -9
- package/public/docs/tuning-reference/joins.html +5 -9
- package/public/docs/tuning-reference/memory-model.html +5 -9
- package/public/docs/tuning-reference/metrics.html +5 -9
- package/public/docs/tuning-reference/partitioning.html +5 -9
- package/public/docs/tuning-reference/pyspark.html +5 -9
- package/public/docs/tuning-reference/shuffle.html +5 -9
- package/public/docs/tuning-reference/spark-architecture.html +5 -9
- package/public/docs/tuning-reference/table-formats.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +5 -9
- package/public/docs/user-guide/alternative-log-retrieval.html +5 -9
- package/public/docs/user-guide/getting-started/ci-and-automation.html +17 -15
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +6 -10
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +5 -9
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +7 -11
- package/public/docs/user-guide/getting-started.html +5 -9
- package/public/docs/user-guide/mcp-tools/compare-runs.html +16 -15
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +28 -11
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +6 -10
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +5 -9
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +7 -10
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +5 -9
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +6 -10
- package/public/docs/user-guide/mcp-tools/list-runs.html +5 -9
- package/public/docs/user-guide/mcp-tools.html +6 -10
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -9
- package/public/docs/user-guide/run-comparison.html +6 -10
- package/public/docs/user-guide/understanding-findings.html +6 -10
- package/public/export-template.html +46 -46
- package/public/favicon.svg +2 -2
- package/public/index.html +8 -10
- package/public/sample-runs/sample-run.ndjson.gz +0 -0
- package/vendor-core/allocation.js +126 -39
- package/vendor-core/analyzer.js +85 -58
- package/vendor-core/api-merge-writes.js +3 -0
- package/vendor-core/aqe-skew.js +347 -0
- package/vendor-core/cli/budgets.js +6 -4
- package/vendor-core/cli/collect-run-pair.js +89 -0
- package/vendor-core/cli/collect-run-worker.js +16 -0
- package/vendor-core/cli/collect-run.js +1 -2
- package/vendor-core/cli/native-zstd.js +12 -16
- package/vendor-core/comparability.js +234 -0
- package/vendor-core/comparison-output.js +15 -7
- package/vendor-core/comparison-verdict.js +105 -25
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/core-time-series.js +0 -1
- package/vendor-core/core-usage-locality.js +1 -1
- package/vendor-core/delta-log-paths.js +10 -1
- package/vendor-core/detectors.js +1078 -416
- package/vendor-core/docs-config.js +0 -4
- package/vendor-core/docs-content/detection/cache.md +2 -1
- package/vendor-core/docs-content/detection/cfg.md +19 -11
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/gc.md +7 -3
- package/vendor-core/docs-content/detection/host.md +11 -1
- package/vendor-core/docs-content/detection/mem.md +17 -6
- package/vendor-core/docs-content/detection/part.md +3 -1
- package/vendor-core/docs-content/detection/plan.md +55 -13
- package/vendor-core/docs-content/detection/shfl.md +11 -5
- package/vendor-core/docs-content/detection/skew.md +48 -1
- package/vendor-core/docs-content/detection/slow.md +4 -2
- package/vendor-core/docs-content/detection/spec.md +6 -1
- package/vendor-core/docs-content/detection/spill.md +6 -3
- package/vendor-core/docs-content/detection/strag.md +19 -6
- package/vendor-core/docs-content/detection/tiny.md +9 -3
- package/vendor-core/docs-content/detection/util.md +6 -2
- package/vendor-core/effective-conf.js +7 -10
- package/vendor-core/efficiency-model.js +24 -16
- package/vendor-core/etl-phases.js +1 -2
- package/vendor-core/event-handlers.js +175 -57
- package/vendor-core/event-schemas.js +21 -16
- package/vendor-core/evidence-availability.js +9 -2
- package/vendor-core/evidence-report.js +118 -35
- package/vendor-core/executor-peaks.js +41 -0
- package/vendor-core/export-data.js +5 -5
- package/vendor-core/finding-identity.js +78 -0
- package/vendor-core/finding-presentation.js +129 -39
- package/vendor-core/finding-types.js +108 -30
- package/vendor-core/format-utils.js +14 -15
- package/vendor-core/html-export.js +1 -1
- package/vendor-core/impact-band.js +2 -2
- package/vendor-core/impact-format.js +47 -19
- package/vendor-core/impact-model.js +28 -17
- package/vendor-core/job-groups.js +4 -4
- package/vendor-core/mcp-server-factory.js +48 -12
- package/vendor-core/mcp-tools.js +179 -24
- package/vendor-core/median.js +2 -2
- package/vendor-core/nested-loop-join.js +73 -0
- package/vendor-core/occupancy.js +1 -2
- package/vendor-core/parser-worker.js +1 -1
- package/vendor-core/plan-graph-model.js +14 -22
- package/vendor-core/plan-node-detail.js +2 -3
- package/vendor-core/plan-summary.js +24 -19
- package/vendor-core/plan-tree-walk.js +6 -8
- package/vendor-core/python-stage.js +12 -1
- package/vendor-core/recommendation-rollup.js +13 -12
- package/vendor-core/redact.js +52 -46
- package/vendor-core/remediation.js +10 -5
- package/vendor-core/run-aggregates.js +6 -8
- package/vendor-core/run-comparison.js +226 -66
- package/vendor-core/run-identity.js +12 -0
- package/vendor-core/run-interpretation.js +21 -0
- package/vendor-core/run-metrics.js +2 -2
- package/vendor-core/run-output.js +44 -11
- package/vendor-core/run-totals.js +12 -0
- package/vendor-core/run-verdict.js +76 -3
- package/vendor-core/scaling-sim.js +3 -4
- package/vendor-core/snappy-block.js +2 -2
- package/vendor-core/spark-conf.js +168 -0
- package/vendor-core/sql-stages.js +2 -2
- package/vendor-core/stage-alignment.js +2 -12
- package/vendor-core/stage-identity.js +58 -3
- package/vendor-core/stage-label.js +14 -0
- package/vendor-core/stage-plan-nodes.js +17 -3
- package/vendor-core/stage-quantiles.js +141 -9
- package/vendor-core/stage-structure.js +17 -3
- package/vendor-core/threshold-overrides.js +9 -3
- package/vendor-core/types.js +70 -23
- package/vendor-core/wall-clock.js +8 -0
- package/vendor-core/wasted-core-hours.js +12 -12
- package/vendor-core/write-targets.js +146 -14
- package/vendor-core/zstd-worker-client.js +1 -1
- package/vendor-core/zstd-worker.js +1 -1
- package/public/assets/AutoscalingChurn-8t3U3isq.js +0 -1
- package/public/assets/CacheUtilization-CJs9tTum.js +0 -1
- package/public/assets/CachingOpportunity-D1NcHs0V.js +0 -1
- package/public/assets/ColdStart-CdRJ9gD8.js +0 -1
- package/public/assets/ConfigAudit-B5Gbe5js.js +0 -1
- package/public/assets/CoreUsageArea-a--NTRGY.js +0 -1
- package/public/assets/Dashboard-C1hNeX49.js +0 -2
- package/public/assets/DisclosureContext-ZpE6CkHx.js +0 -1
- package/public/assets/DuplicatePlanSubtree-dobXdz7E.js +0 -1
- package/public/assets/ExecutorUtilization-D9grwi7t.js +0 -1
- package/public/assets/GcPressure-8-G2ri10.js +0 -1
- package/public/assets/IncompleteRun-B91lky7a.js +0 -1
- package/public/assets/JobFailures-BsWvBMyJ.js +0 -1
- package/public/assets/MemoryUtilization-BM5schZI.js +0 -1
- package/public/assets/OverBroadcast-DdN8JIJH.js +0 -1
- package/public/assets/PartitionHint-CUvbnnxy.js +0 -1
- package/public/assets/PartitionSizing-CY5HDYtp.js +0 -1
- package/public/assets/PlanExplorer-DgHCDBD_.js +0 -1
- package/public/assets/PlanGraphRoute-DH3KJb8j.js +0 -1
- package/public/assets/RetryWaste-DOnE9vGF.js +0 -1
- package/public/assets/ShuffleIO-MMnDESkF.js +0 -1
- package/public/assets/Skew-BmZZJ5ms.js +0 -1
- package/public/assets/SlowHost-CsJzfEqo.js +0 -1
- package/public/assets/SmallFiles-BoK3R1Ex.js +0 -1
- package/public/assets/SpeculationWaste-CnVxB5AJ.js +0 -1
- package/public/assets/Spill-BhNicyBy.js +0 -1
- package/public/assets/StageFailed-mAhHU4l_.js +0 -1
- package/public/assets/StageFindingGroup-BEtPWcT0.js +0 -1
- package/public/assets/StageHeader-DJkYkrsU.js +0 -1
- package/public/assets/StageShape-BDxRknLp.js +0 -1
- package/public/assets/StageSlowness-BPRw-otN.js +0 -1
- package/public/assets/Straggler-CZCbnOWP.js +0 -1
- package/public/assets/TaskFailures-C57YcLFQ.js +0 -1
- package/public/assets/TinyTask-Bi84qU7n.js +0 -1
- package/public/assets/UnderBroadcast-DdQV7htE.js +0 -1
- package/public/assets/charts-vendor-0VMaLVLN.js +0 -59
- package/public/assets/finding-anchor-Cl6_5hfV.js +0 -1
- package/public/assets/impact-sort-CssZ6MT2.js +0 -1
- package/public/assets/index-2h_TgUAb.css +0 -2
- package/public/assets/index-B-03mG7K.js +0 -14
- package/public/assets/plan-graph-vendor-BYl-AzN5.js +0 -7
- package/public/assets/react-vendor-DEdfrRTJ.js +0 -9
- package/public/assets/select-CQjNhprm.js +0 -1
- package/public/assets/usePagedRows-Dyl6T8Ok.js +0 -1
- package/public/assets/useRecentFiles-XZEnLlal.js +0 -11
- package/public/assets/useSortMode-Dhvit8dt.js +0 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.u_e5bQz4.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets.md.YQcj5EI4.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_plan-advisor.md.RlzvUmNm.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_board-widgets_visual-system-and-templating.md.DYgUpIJB.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract.md.wj6Et6UD.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_plan-attribution.md.yNex4bys.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_drill-down_plan-graph.md.DwOozIEs.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation.md.CZv_ZGOp.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_caveats-tuning-and-coverage.md.BUucRc0A.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_impact-estimation_stage-union-rollup.md.DdCGtAGu.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_overview.md.C1sSvm9i.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering.md.BOZ1azXG.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_widget-rendering_findings-tab.md.BQXycK6G.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol.md.BAnhi2-d.lean.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_evidence-report.md.DVGZOWvW.js +0 -1
- package/public/docs/assets/contributor-guide_contributing.md.CQMvGwFt.js +0 -1
- package/public/docs/assets/contributor-guide_development-setup.md.D9bu4j_c.lean.js +0 -1
- package/public/docs/assets/contributor-guide_testing.md.By6XGR9a.js +0 -1
- package/public/docs/assets/inter-italic-cyrillic-ext.r48I6akx.woff2 +0 -0
- package/public/docs/assets/inter-italic-cyrillic.By2_1cv3.woff2 +0 -0
- package/public/docs/assets/inter-italic-greek-ext.1u6EdAuj.woff2 +0 -0
- package/public/docs/assets/inter-italic-greek.DJ8dCoTZ.woff2 +0 -0
- package/public/docs/assets/inter-italic-latin-ext.CN1xVJS-.woff2 +0 -0
- package/public/docs/assets/inter-italic-latin.C2AdPX0b.woff2 +0 -0
- package/public/docs/assets/inter-italic-vietnamese.BSbpV94h.woff2 +0 -0
- package/public/docs/assets/inter-roman-cyrillic-ext.BBPuwvHQ.woff2 +0 -0
- package/public/docs/assets/inter-roman-cyrillic.C5lxZ8CY.woff2 +0 -0
- package/public/docs/assets/inter-roman-greek-ext.CqjqNYQ-.woff2 +0 -0
- package/public/docs/assets/inter-roman-greek.BBVDIX6e.woff2 +0 -0
- package/public/docs/assets/inter-roman-latin-ext.4ZJIpNVo.woff2 +0 -0
- package/public/docs/assets/inter-roman-latin.Di8DUHzh.woff2 +0 -0
- package/public/docs/assets/inter-roman-vietnamese.BjW4sHH5.woff2 +0 -0
- package/public/docs/assets/style.tmDhD3c8.css +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.js +0 -23
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.lean.js +0 -1
- package/public/docs/assets/user-guide_getting-started_reading-the-dashboard.md.Obf3W3__.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js +0 -1
- package/public/docs/assets/user-guide_mcp-tools_diagnose-run.md.BP1vnHA5.js +0 -23
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.lean.js +0 -1
- /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
- /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
- /package/public/docs/assets/{contributor-guide_architecture_overview.md.C1sSvm9i.lean.js → contributor-guide_architecture_overview.md.nxkpOhgf.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_widget-rendering.md.BOZ1azXG.lean.js → contributor-guide_architecture_widget-rendering.md.BrSz8Ezh.lean.js} +0 -0
- /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
- /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
- /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
- /package/public/docs/assets/{contributor-guide_contributing.md.CQMvGwFt.lean.js → contributor-guide_contributing.md.DBW4drtZ.lean.js} +0 -0
- /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
- /package/public/docs/assets/{user-guide_mcp-tools.md.C65SjWUL.lean.js → user-guide_mcp-tools.md.49r3L2YE.lean.js} +0 -0
- /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
|
@@ -6,41 +6,79 @@ import { totalExecutorCpuMs, withEarlierAttempts } from './run-totals.js';
|
|
|
6
6
|
import { captureSnapshot } from './session-snapshot.js';
|
|
7
7
|
import { alignStages, compileNormalizePatterns, COMPARISON_SCHEMA_VERSION, } from './stage-alignment.js';
|
|
8
8
|
import { tunedRunNote } from './threshold-overrides.js';
|
|
9
|
-
|
|
9
|
+
import { diffFindings, findingBand, findingKey, findingRule, } from './finding-identity.js';
|
|
10
|
+
import { cyrb53 } from './string-hash.js';
|
|
11
|
+
import { IMPACT_BAND_ORDER } from './format-utils.js';
|
|
12
|
+
|
|
10
13
|
|
|
11
14
|
|
|
12
15
|
import { isIncompleteRun } from './check-coverage.js';
|
|
16
|
+
import { stageDisplayLabel } from './stage-label.js';
|
|
17
|
+
import { runAppIdentity, } from './run-identity.js';
|
|
13
18
|
import { summarizeRunOutcome } from './run-outcome.js';
|
|
19
|
+
import { buildComparability, withinBand, } from './comparability.js';
|
|
14
20
|
|
|
15
21
|
|
|
16
22
|
|
|
17
23
|
|
|
18
24
|
|
|
19
25
|
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
20
29
|
|
|
30
|
+
// An introduced or resolved finding category: the findings of one rule and band that have no
|
|
31
|
+
// counterpart in the other run. An introduced row has `baseCount` 0, a resolved row `candCount` 0.
|
|
32
|
+
// `keys`: the `key` of each finding the row counts, as `diagnose_run` reports it for the run the
|
|
33
|
+
// findings are in (the candidate for an introduced row, the baseline for a resolved one).
|
|
21
34
|
|
|
22
35
|
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
// Findings both runs have, at one location, that moved from one impact band to another. `count`
|
|
41
|
+
// is how many findings of that rule moved between those two bands.
|
|
42
|
+
// `keys` are the candidate run's finding keys, `baseKeys` the baseline's: a pair the aligner matched
|
|
43
|
+
// without an exact fingerprint match has different keys on the two sides.
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
/** True when a changed finding moved to a more severe band (an unknown band ranks least severe). */
|
|
51
|
+
export function isEscalation(row ) {
|
|
52
|
+
const rank = (band ) => IMPACT_BAND_ORDER[band ] ?? 9;
|
|
53
|
+
return rank(row.candImpactBand) < rank(row.baseImpactBand);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
|
|
23
57
|
|
|
24
58
|
|
|
25
59
|
|
|
26
60
|
|
|
27
61
|
|
|
62
|
+
/** A stage pair with its stage name as a display label (call-site directories removed). The pair
|
|
63
|
+
* carries no raw name, so the label is the only name on the row. */
|
|
64
|
+
|
|
28
65
|
|
|
29
66
|
|
|
67
|
+
|
|
30
68
|
|
|
31
69
|
|
|
32
|
-
|
|
70
|
+
|
|
33
71
|
|
|
34
72
|
|
|
35
73
|
|
|
36
74
|
|
|
37
|
-
|
|
75
|
+
|
|
38
76
|
|
|
39
77
|
|
|
40
78
|
|
|
41
79
|
|
|
42
80
|
|
|
43
|
-
|
|
81
|
+
|
|
44
82
|
|
|
45
83
|
|
|
46
84
|
|
|
@@ -48,6 +86,7 @@ import { summarizeRunOutcome } from './run-outcome.js';
|
|
|
48
86
|
|
|
49
87
|
|
|
50
88
|
|
|
89
|
+
|
|
51
90
|
|
|
52
91
|
|
|
53
92
|
function jobOutcome(snapshot ) {
|
|
@@ -61,6 +100,41 @@ export function stageIdentity(stage , snapshot
|
|
|
61
100
|
return stageIdentityWith(stage, snapshot, normalizeDetail);
|
|
62
101
|
}
|
|
63
102
|
|
|
103
|
+
/** The key a finding row carries (`findingKey`: type, rule and location) with the location read off
|
|
104
|
+
* the run alone: a stage by its `stageIdentity` fingerprint (the keys of `metrics.stages`), an SQL
|
|
105
|
+
* execution by a digest of its stages' fingerprints. Two runs of the same job give the same finding
|
|
106
|
+
* the same key, so a reader pairs findings across runs without the aligner. A pairing aid: several
|
|
107
|
+
* findings can share a key (one detector firing per host on a run-level key, stages that share a
|
|
108
|
+
* fingerprint), and it says nothing about whether the finding's value or band held. */
|
|
109
|
+
export function findingKeyer(snapshot ) {
|
|
110
|
+
const stageLabels = new Map ();
|
|
111
|
+
const stageLabel = (id ) => {
|
|
112
|
+
let label = stageLabels.get(id);
|
|
113
|
+
if (label === undefined) {
|
|
114
|
+
const stage = snapshot.stages.get(id);
|
|
115
|
+
label = stage ? stageIdentity(stage, snapshot) : `#${id}`;
|
|
116
|
+
stageLabels.set(id, label);
|
|
117
|
+
}
|
|
118
|
+
return label;
|
|
119
|
+
};
|
|
120
|
+
let stagesByExecution ;
|
|
121
|
+
const executionLabel = (id ) => {
|
|
122
|
+
if (!stagesByExecution) {
|
|
123
|
+
stagesByExecution = new Map();
|
|
124
|
+
for (const [stageId, stage] of snapshot.stages) {
|
|
125
|
+
if (stage.sqlExecutionId == null) continue;
|
|
126
|
+
const ids = stagesByExecution.get(stage.sqlExecutionId);
|
|
127
|
+
if (ids) ids.push(stageId); else stagesByExecution.set(stage.sqlExecutionId, [stageId]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const ids = stagesByExecution.get(id);
|
|
131
|
+
// An execution with no stage has no fingerprint to digest: its id is all that names it.
|
|
132
|
+
return ids ? cyrb53(JSON.stringify(ids.map(stageLabel).sort())) : `#${id}`;
|
|
133
|
+
};
|
|
134
|
+
const locator = { stage: stageLabel, execution: executionLabel };
|
|
135
|
+
return (finding) => findingKey(finding, locator);
|
|
136
|
+
}
|
|
137
|
+
|
|
64
138
|
export function matchStages(baseSnap , candSnap )
|
|
65
139
|
|
|
66
140
|
|
|
@@ -135,13 +209,9 @@ export const COMPARISON_METRIC_KEYS = [
|
|
|
135
209
|
'executorCpuTime', 'allocatedCoreHours',
|
|
136
210
|
];
|
|
137
211
|
|
|
138
|
-
// Volume/count metrics
|
|
139
|
-
//
|
|
140
|
-
//
|
|
141
|
-
// single source of truth for "which metrics have no better/worse direction",
|
|
142
|
-
// shared by the view (RunComparison.tsx, for Δ coloring) and by
|
|
143
|
-
// src/cli/budgets.ts's checkRegression (so a `--regression-metric inputBytes`
|
|
144
|
-
// budget can't misread "processed more data" as a regression).
|
|
212
|
+
// Volume/count metrics have no better/worse direction: more input, output, tasks or executors may
|
|
213
|
+
// just reflect a differently-sized job. Shared by the view (Δ coloring) and by the CLI's
|
|
214
|
+
// checkRegression, so a `--regression-metric inputBytes` budget cannot read more data as a regression.
|
|
145
215
|
export const NEUTRAL_METRIC_KEYS = new Set(['inputBytes', 'outputBytes', 'taskCount', 'executorsAdded']);
|
|
146
216
|
|
|
147
217
|
function direction(key , baseline , candidate ) {
|
|
@@ -151,16 +221,21 @@ function direction(key , baseline , candidate
|
|
|
151
221
|
return d < 0 ? 'improvement' : d > 0 ? 'regression' : 'unchanged';
|
|
152
222
|
}
|
|
153
223
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
) {
|
|
158
|
-
const dir = direction(key, baseline, candidate);
|
|
159
|
-
const delta = baseline == null || candidate == null ? null : candidate - baseline;
|
|
160
|
-
return { key, label, baseline, candidate, delta, direction: dir, ...extra };
|
|
161
|
-
}
|
|
224
|
+
/** A change under this share of the baseline's value is within run-to-run noise: a shared cluster
|
|
225
|
+
* easily moves a job a percent or two. The caller's `noiseBand` replaces it. */
|
|
226
|
+
export const DEFAULT_NOISE_BAND = 0.02;
|
|
162
227
|
|
|
163
|
-
export function metricDeltas(baseSnap , candSnap ) {
|
|
228
|
+
export function metricDeltas(baseSnap , candSnap , noiseBand = DEFAULT_NOISE_BAND) {
|
|
229
|
+
const metric = (
|
|
230
|
+
key , label , baseline , candidate ,
|
|
231
|
+
extra = {},
|
|
232
|
+
) => {
|
|
233
|
+
const delta = baseline == null || candidate == null ? null : candidate - baseline;
|
|
234
|
+
return {
|
|
235
|
+
key, label, baseline, candidate, delta, direction: direction(key, baseline, candidate),
|
|
236
|
+
withinNoise: baseline != null && candidate != null && withinBand(baseline, candidate, noiseBand), ...extra,
|
|
237
|
+
};
|
|
238
|
+
};
|
|
164
239
|
const out = [];
|
|
165
240
|
// Run totals count every task attempt, failed and speculative ones too (run-totals.ts), the
|
|
166
241
|
// same sums the CLI metrics block reports; skew stays on each stage's latest attempt.
|
|
@@ -238,44 +313,84 @@ export function metricDeltas(baseSnap , candSnap
|
|
|
238
313
|
return out;
|
|
239
314
|
}
|
|
240
315
|
|
|
241
|
-
//
|
|
242
|
-
//
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
const
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
316
|
+
// Cross-run identity of a snapshot's stages and SQL executions: a stage (or execution) the aligner
|
|
317
|
+
// paired takes one label on both sides; an unpaired one takes a side-neutral label, so the same problem on an unpaired stage in both runs still matches.
|
|
318
|
+
function findingLocators(baseSnap , candSnap , stagePairs ) {
|
|
319
|
+
const baseStage = new Map (), candStage = new Map ();
|
|
320
|
+
const executionVotes = new Map (); // base execution -> cand execution -> paired stages
|
|
321
|
+
for (const pair of stagePairs) {
|
|
322
|
+
baseStage.set(pair.baseStageIds[0], pair.pairId);
|
|
323
|
+
candStage.set(pair.candStageIds[0], pair.pairId);
|
|
324
|
+
const baseExec = baseSnap.stages.get(pair.baseStageIds[0])?.sqlExecutionId;
|
|
325
|
+
const candExec = candSnap.stages.get(pair.candStageIds[0])?.sqlExecutionId;
|
|
326
|
+
if (baseExec == null || candExec == null) continue;
|
|
327
|
+
const votes = executionVotes.get(baseExec) ?? new Map ();
|
|
328
|
+
votes.set(candExec, (votes.get(candExec) ?? 0) + 1);
|
|
329
|
+
executionVotes.set(baseExec, votes);
|
|
330
|
+
}
|
|
331
|
+
// An execution pairs with the candidate execution that holds most of its paired stages.
|
|
332
|
+
const executionPair = new Map ();
|
|
333
|
+
for (const [baseExec, votes] of executionVotes) {
|
|
334
|
+
const [candExec] = [...votes].sort((a, b) => b[1] - a[1] || a[0] - b[0])[0];
|
|
335
|
+
executionPair.set(baseExec, candExec);
|
|
336
|
+
}
|
|
337
|
+
const pairedCandExecs = new Set(executionPair.values());
|
|
338
|
+
return {
|
|
339
|
+
base: { stage: (id) => baseStage.get(id) ?? 'unpaired', execution: (id) => executionPair.has(id) ? `c${executionPair.get(id)}` : 'unpaired' },
|
|
340
|
+
cand: { stage: (id) => candStage.get(id) ?? 'unpaired', execution: (id) => pairedCandExecs.has(id) ? `c${id}` : 'unpaired' },
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// A finding is the same finding in both runs when `findingKey` says so (type, rule and location,
|
|
345
|
+
// never value or band). One with a counterpart is not introduced or resolved: a different band
|
|
346
|
+
// makes it `changed`. Each row aggregates findings of one rule and band, with the stage names
|
|
347
|
+
// of the side the findings are on.
|
|
348
|
+
export function findingsDelta(baseSnap , candSnap , stagePairs = []) {
|
|
349
|
+
const locators = findingLocators(baseSnap, candSnap, stagePairs);
|
|
350
|
+
const diff = diffFindings(baseSnap.catalog, candSnap.catalog, locators.base, locators.cand);
|
|
351
|
+
const stageNames = (snap , findings ) => {
|
|
352
|
+
const names = new Set ();
|
|
353
|
+
for (const f of findings) {
|
|
354
|
+
const name = f.stageId != null ? snap.stages.get(f.stageId)?.name : undefined;
|
|
355
|
+
if (name) names.add(name);
|
|
262
356
|
}
|
|
263
|
-
return
|
|
357
|
+
return [...names].sort();
|
|
264
358
|
};
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
const
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
359
|
+
const stageLabelsOf = (names ) => [...new Set(names.map(stageDisplayLabel))].sort();
|
|
360
|
+
const baseKeyOf = findingKeyer(baseSnap), candKeyOf = findingKeyer(candSnap);
|
|
361
|
+
const keysOf = (findings , keyOf ) => [...new Set(findings.map(keyOf))].sort();
|
|
362
|
+
const group = (items , keyOf ) => {
|
|
363
|
+
const groups = new Map ();
|
|
364
|
+
for (const item of items) {
|
|
365
|
+
const key = keyOf(item);
|
|
366
|
+
const members = groups.get(key);
|
|
367
|
+
if (members) members.push(item); else groups.set(key, [item]);
|
|
368
|
+
}
|
|
369
|
+
return [...groups].sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0));
|
|
370
|
+
};
|
|
371
|
+
const rows = (findings , snap , side ) =>
|
|
372
|
+
group(findings, (f) => `${findingRule(f)}§${findingBand(f)}`).map(([, fs]) => {
|
|
373
|
+
const count = fs.length;
|
|
374
|
+
const stages = stageNames(snap, fs);
|
|
375
|
+
return {
|
|
376
|
+
rule: findingRule(fs[0]), type: fs[0].type, impactBand: findingBand(fs[0]),
|
|
377
|
+
baseCount: side === 'base' ? count : 0, candCount: side === 'cand' ? count : 0,
|
|
378
|
+
delta: side === 'cand' ? count : -count, stages, stageLabels: stageLabelsOf(stages),
|
|
379
|
+
keys: keysOf(fs, side === 'cand' ? candKeyOf : baseKeyOf),
|
|
380
|
+
};
|
|
381
|
+
});
|
|
382
|
+
const changed = group(
|
|
383
|
+
diff.changed, (c) => `${findingRule(c.candidate)}§${findingBand(c.baseline)}§${findingBand(c.candidate)}`,
|
|
384
|
+
).map(([, cs]) => {
|
|
385
|
+
const stages = stageNames(candSnap, cs.map((c) => c.candidate));
|
|
386
|
+
return {
|
|
387
|
+
rule: findingRule(cs[0].candidate), type: cs[0].candidate.type,
|
|
388
|
+
baseImpactBand: findingBand(cs[0].baseline), candImpactBand: findingBand(cs[0].candidate),
|
|
389
|
+
count: cs.length, stages, stageLabels: stageLabelsOf(stages),
|
|
390
|
+
keys: keysOf(cs.map((c) => c.candidate), candKeyOf), baseKeys: keysOf(cs.map((c) => c.baseline), baseKeyOf),
|
|
391
|
+
};
|
|
392
|
+
});
|
|
393
|
+
return { introduced: rows(diff.introduced, candSnap, 'cand'), resolved: rows(diff.resolved, baseSnap, 'base'), changed };
|
|
279
394
|
}
|
|
280
395
|
|
|
281
396
|
function namesConflict(a , b ) {
|
|
@@ -340,16 +455,23 @@ const EMPTY_TASK_DATA = new Map ();
|
|
|
340
455
|
|
|
341
456
|
|
|
342
457
|
|
|
343
|
-
|
|
458
|
+
|
|
344
459
|
|
|
345
460
|
|
|
461
|
+
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
|
|
346
471
|
|
|
347
472
|
|
|
348
|
-
//
|
|
349
|
-
//
|
|
350
|
-
// captureSnapshot (with an empty taskDataCache, the interactive drill-down
|
|
351
|
-
// cache, never read by compareRuns/matchStages/metricDeltas/findingsDelta)
|
|
352
|
-
// for each side before diffing them.
|
|
473
|
+
// Snapshot-building shared by the CLI's --baseline path and mcp-tools.ts's compareRuns tool. The
|
|
474
|
+
// empty taskDataCache is the interactive drill-down cache, which comparison never reads.
|
|
353
475
|
export function buildComparison(
|
|
354
476
|
baseline ,
|
|
355
477
|
candidate ,
|
|
@@ -373,7 +495,11 @@ export function compareRuns(
|
|
|
373
495
|
options = {},
|
|
374
496
|
) {
|
|
375
497
|
const baseSnap = baseline.snapshot, candSnap = candidate.snapshot;
|
|
376
|
-
|
|
498
|
+
const noiseBand = options.noiseBand ?? DEFAULT_NOISE_BAND;
|
|
499
|
+
if (!Number.isFinite(noiseBand) || noiseBand < 0 || noiseBand > 1) {
|
|
500
|
+
throw new Error(`noiseBand must be a number from 0 to 1, got ${noiseBand}.`);
|
|
501
|
+
}
|
|
502
|
+
// `matchedCoverage` comes from the exact matcher; pairs and the gate come from the aligner.
|
|
377
503
|
const match = matchStages(baseSnap, candSnap);
|
|
378
504
|
const alignment = alignStages(baseSnap, candSnap, { normalizePath: compileNormalizePatterns(options.normalizePath) });
|
|
379
505
|
const runtimeCoverage = alignment.runtimeCoverage;
|
|
@@ -398,24 +524,29 @@ export function compareRuns(
|
|
|
398
524
|
: lowCoverage
|
|
399
525
|
? `Only ${share} of executor run time is in matched stages, so per-stage rows mostly compare unrelated work.`
|
|
400
526
|
: null;
|
|
527
|
+
const metrics = metricDeltas(baseSnap, candSnap, noiseBand);
|
|
401
528
|
return {
|
|
402
529
|
baselineLabel: baseline.label, candidateLabel: candidate.label,
|
|
530
|
+
baselineApp: runAppIdentity(baseSnap.app), candidateApp: runAppIdentity(candSnap.app),
|
|
403
531
|
confidence,
|
|
404
532
|
reason,
|
|
405
533
|
matchedCoverage: match.coverage,
|
|
406
534
|
comparisonSchemaVersion: COMPARISON_SCHEMA_VERSION,
|
|
407
535
|
runtimeCoverage,
|
|
408
|
-
stagePairs: alignment.pairs
|
|
536
|
+
stagePairs: alignment.pairs.map((p) => ({
|
|
537
|
+
...p, stageLabel: stageDisplayLabel(baseSnap.stages.get(p.baseStageIds[0])?.name ?? ''),
|
|
538
|
+
})),
|
|
409
539
|
unmatched: alignment.unmatched,
|
|
410
540
|
replanned: alignment.replanned,
|
|
411
541
|
bookkeepingStageIds: alignment.bookkeepingStageIds,
|
|
412
542
|
executionAlignment: alignment.executionAlignment,
|
|
413
|
-
metrics
|
|
414
|
-
findings: findingsDelta(baseSnap, candSnap),
|
|
543
|
+
metrics,
|
|
544
|
+
findings: findingsDelta(baseSnap, candSnap, alignment.pairs),
|
|
415
545
|
stageSkew: stageSkewDeltas(baseSnap, candSnap, alignment.pairs),
|
|
416
546
|
baseStages: stageList(baseSnap),
|
|
417
547
|
candStages: stageList(candSnap),
|
|
418
548
|
jobOutcomes: { baseline: jobOutcome(baseSnap), candidate: jobOutcome(candSnap) },
|
|
549
|
+
comparability: buildComparability(baseSnap, candSnap, alignment, metrics, { ignoreConf: options.ignoreConf, confRedactRegex: options.confRedactRegex, noiseBand }),
|
|
419
550
|
};
|
|
420
551
|
}
|
|
421
552
|
|
|
@@ -429,6 +560,31 @@ function renderFindingsSection(title , findings )
|
|
|
429
560
|
return lines;
|
|
430
561
|
}
|
|
431
562
|
|
|
563
|
+
// Findings both runs have whose impact band moved: `### Changed findings (<count>)`, one bullet each.
|
|
564
|
+
function renderChangedSection(changed ) {
|
|
565
|
+
const lines = [`### Changed findings (${changed.length})`, ''];
|
|
566
|
+
for (const f of changed) {
|
|
567
|
+
lines.push(`- ${f.rule}: ${f.baseImpactBand} -> ${f.candImpactBand}${f.count > 1 ? ` (${f.count} findings)` : ''}`);
|
|
568
|
+
}
|
|
569
|
+
return lines;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
// What the runs share, as `- key: value` bullets: configuration, plan, data volume and executors.
|
|
573
|
+
function renderComparabilitySection({ conf, plan, volume, capacity } ) {
|
|
574
|
+
const confLine = conf.equal == null ? 'a run records no Spark properties'
|
|
575
|
+
: conf.equal ? 'same' : `${conf.differences.length} differ (${conf.differences.map((d) => d.key).join(', ')})`;
|
|
576
|
+
const pair = (f ) => `${f.baseline ?? 'n/a'} -> ${f.candidate ?? 'n/a'}`;
|
|
577
|
+
const execs = (side ) =>
|
|
578
|
+
`${side.meanExecutors == null ? 'n/a' : side.meanExecutors.toFixed(1)} mean / ${side.peakExecutors ?? 'n/a'} peak`;
|
|
579
|
+
return [
|
|
580
|
+
'### Comparability', '',
|
|
581
|
+
`- configuration: ${confLine}`,
|
|
582
|
+
`- plan: ${plan.equal ? 'every stage pairs' : `${plan.unmatched.baseline} baseline / ${plan.unmatched.candidate} candidate stages unmatched, ${plan.replanned} re-planned`}`,
|
|
583
|
+
`- input bytes: ${pair(volume.inputBytes)}, output rows: ${pair(volume.outputRows)}, output bytes: ${pair(volume.outputBytes)}`,
|
|
584
|
+
`- executors: ${execs(capacity.baseline)} -> ${execs(capacity.candidate)}`,
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
|
|
432
588
|
// Small Markdown renderer for the comparison section, matching
|
|
433
589
|
// evidence-report.ts's renderMarkdown house style (## section heading, ###
|
|
434
590
|
// subheadings, `- key: value` bullets). Shared by the CLI's --baseline
|
|
@@ -458,6 +614,8 @@ export function renderComparisonMarkdown(
|
|
|
458
614
|
lines.push(`- runtime coverage: ${comparison.runtimeCoverage === null ? 'n/a' : `${(comparison.runtimeCoverage * 100).toFixed(1)}%`}`);
|
|
459
615
|
lines.push(`- stage pairs: ${comparison.stagePairs.length}, unmatched: ${comparison.unmatched.baseStageIds.length} baseline / ${comparison.unmatched.candStageIds.length} candidate, Delta bookkeeping: ${comparison.bookkeepingStageIds.baseStageIds.length} baseline / ${comparison.bookkeepingStageIds.candStageIds.length} candidate`);
|
|
460
616
|
lines.push('');
|
|
617
|
+
lines.push(...renderComparabilitySection(comparison.comparability));
|
|
618
|
+
lines.push('');
|
|
461
619
|
lines.push('### Metric deltas');
|
|
462
620
|
lines.push('');
|
|
463
621
|
for (const m of comparison.metrics) {
|
|
@@ -467,5 +625,7 @@ export function renderComparisonMarkdown(
|
|
|
467
625
|
lines.push(...renderFindingsSection('Introduced findings', comparison.findings.introduced));
|
|
468
626
|
lines.push('');
|
|
469
627
|
lines.push(...renderFindingsSection('Resolved findings', comparison.findings.resolved));
|
|
628
|
+
lines.push('');
|
|
629
|
+
lines.push(...renderChangedSection(comparison.findings.changed));
|
|
470
630
|
return lines.join('\n');
|
|
471
631
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
|
|
2
|
+
|
|
3
|
+
/** Which Spark application a report describes: its id and attempt id, null where the log has none
|
|
4
|
+
* (an attempt id is written only by a cluster-mode run). */
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export function runAppIdentity(app ) {
|
|
11
|
+
return { id: app?.id ?? null, attemptId: typeof app?.attemptId === 'string' ? app.attemptId : null };
|
|
12
|
+
}
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from './run-verdict.js';
|
|
23
23
|
import { recommendationText } from './finding-names.js';
|
|
24
24
|
import { getScorecardEstimates } from './scorecard-estimates.js';
|
|
25
|
+
import { singleStageId } from './finding-filter-predicate.js';
|
|
25
26
|
import { checkConcurrentJobGroups } from './job-groups.js';
|
|
26
27
|
import { computeWallClock } from './wall-clock.js';
|
|
27
28
|
import { computeWastedCoreHours, } from './wasted-core-hours.js';
|
|
@@ -57,6 +58,15 @@ import { computeWastedCoreHours, } from './wasted-cor
|
|
|
57
58
|
|
|
58
59
|
|
|
59
60
|
|
|
61
|
+
/** One cost-lane entry: a finding ranked by the measured busy core time its fix removes.
|
|
62
|
+
* `leadIndex` names the finding. */
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
60
70
|
|
|
61
71
|
|
|
62
72
|
|
|
@@ -64,7 +74,12 @@ import { computeWastedCoreHours, } from './wasted-cor
|
|
|
64
74
|
|
|
65
75
|
|
|
66
76
|
|
|
77
|
+
|
|
67
78
|
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
|
|
68
83
|
|
|
69
84
|
|
|
70
85
|
|
|
@@ -265,6 +280,12 @@ export function interpretRun(appModel , catalog , configFindi
|
|
|
265
280
|
clean: verdict.facts.clean,
|
|
266
281
|
failureReason: outcome.reason,
|
|
267
282
|
steps,
|
|
283
|
+
costSteps: verdict.costLane.map(({ finding, figure }) => ({
|
|
284
|
+
leadIndex: indexOf.get(finding) ,
|
|
285
|
+
stageId: singleStageId(finding),
|
|
286
|
+
figure,
|
|
287
|
+
})),
|
|
288
|
+
idleLine: verdict.idle?.text ?? null,
|
|
268
289
|
remaining: verdict.remaining,
|
|
269
290
|
copyText: verdict.copyText,
|
|
270
291
|
},
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// moves independently of the evidence report's. A figure the log cannot provide is null, never 0.
|
|
4
4
|
import { computeAllocation, } from './allocation.js';
|
|
5
5
|
import { computeSkewRatio, ENTRY_BY_TYPE, } from './detectors.js';
|
|
6
|
-
import { totalExecutorCpuMs, withEarlierAttempts } from './run-totals.js';
|
|
6
|
+
import { totalExecutorCpuMs, totalOutputRows, withEarlierAttempts } from './run-totals.js';
|
|
7
7
|
import { isPythonStage } from './python-stage.js';
|
|
8
8
|
import { stageIdentity } from './run-comparison.js';
|
|
9
9
|
import { hasCompleteApplicationInterval } from './scorecard-estimates.js';
|
|
@@ -128,7 +128,7 @@ function stageMetrics(stages , minTasksForP95 ) {
|
|
|
128
128
|
shuffleWriteBytes: fromTasks((s) => s.shuffleWriteBytes),
|
|
129
129
|
inputBytes: fromTasks((s) => s.inputBytes),
|
|
130
130
|
outputBytes: fromTasks((s) => s.outputBytes),
|
|
131
|
-
outputRows:
|
|
131
|
+
outputRows: totalOutputRows(attempts),
|
|
132
132
|
peakExecutionMemoryBytes: peakExecutionMemory(finished),
|
|
133
133
|
taskCount: tasks != null && tasks > 0 ? tasks : null,
|
|
134
134
|
failedTasks: fromTasks((s) => s.failedTasks),
|
|
@@ -1,26 +1,59 @@
|
|
|
1
|
-
import { runFindings
|
|
1
|
+
import { cacheFor, runFindings, } from './evidence-report.js';
|
|
2
2
|
import { redactRunModel } from './redact.js';
|
|
3
3
|
import { computeRunMetrics, } from './run-metrics.js';
|
|
4
4
|
import { buildEffectiveConf, } from './effective-conf.js';
|
|
5
|
+
import { runAppIdentity, } from './run-identity.js';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
|
|
9
|
+
/** Which build wrote a report: the host package's name and version, and the build id of the core it
|
|
10
|
+
* loaded. Core does not know its host, so the surface passes it in. */
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
// One entry per run model and threshold overrides, kept apart for the plain and the redacted model.
|
|
20
|
+
// A WeakMap needs no invalidation: the entry is collectible once the model is (see runFindings).
|
|
21
|
+
const plainBlocksCache = new WeakMap();
|
|
22
|
+
const redactedBlocksCache = new WeakMap();
|
|
23
|
+
|
|
24
|
+
// The app the blocks read (redacted under `redact`) and the run's `metrics`, the costly part,
|
|
25
|
+
// computed once per run and options.
|
|
26
|
+
function runBlocksBase(appModel , redact , thresholds ) {
|
|
27
|
+
const cache = cacheFor(redact ? redactedBlocksCache : plainBlocksCache, thresholds);
|
|
28
|
+
const cached = cache.get(appModel);
|
|
29
|
+
if (cached) return cached;
|
|
30
|
+
let blocksModel = appModel;
|
|
31
|
+
if (redact) {
|
|
32
|
+
const { catalog, config } = runFindings(appModel, thresholds);
|
|
33
|
+
blocksModel = redactRunModel(appModel, catalog, config).appModel;
|
|
34
|
+
}
|
|
35
|
+
const base = { app: blocksModel.app, metrics: computeRunMetrics(blocksModel, thresholds) };
|
|
36
|
+
cache.set(appModel, base);
|
|
37
|
+
return base;
|
|
38
|
+
}
|
|
39
|
+
|
|
8
40
|
/** The CLI report's `metrics` and `effectiveConf` blocks, shared with MCP diagnose_run. Under
|
|
9
41
|
* `redact` they come from the run redacted with the report's own inputs, so host and app
|
|
10
|
-
* pseudonyms match the report's. `confKeys`/`confRedactRegex` narrow and mask `effectiveConf`.
|
|
42
|
+
* pseudonyms match the report's. `confKeys`/`confRedactRegex` narrow and mask `effectiveConf`.
|
|
43
|
+
* `generator`, when the surface supplies it, is returned as given: it holds no run identifiers.
|
|
44
|
+
* `app` names the Spark application (redacted under `redact`), so two reports can be told apart. */
|
|
11
45
|
export function runOutputBlocks(
|
|
12
46
|
appModel ,
|
|
13
|
-
{ redact, thresholds, confKeys, confRedactRegex }
|
|
47
|
+
{ redact, thresholds, confKeys, confRedactRegex, generator }
|
|
14
48
|
|
|
49
|
+
|
|
15
50
|
= {},
|
|
16
|
-
)
|
|
17
|
-
|
|
18
|
-
if (redact) {
|
|
19
|
-
const { catalog, config } = runFindings(appModel, thresholds);
|
|
20
|
-
blocksModel = redactRunModel(appModel, catalog, config).appModel;
|
|
21
|
-
}
|
|
51
|
+
) {
|
|
52
|
+
const { app, metrics } = runBlocksBase(appModel, redact, thresholds);
|
|
22
53
|
return {
|
|
23
|
-
|
|
24
|
-
|
|
54
|
+
...(generator ? { generator } : {}),
|
|
55
|
+
app: runAppIdentity(app),
|
|
56
|
+
metrics,
|
|
57
|
+
effectiveConf: buildEffectiveConf(app, { keys: confKeys, userPattern: confRedactRegex }),
|
|
25
58
|
};
|
|
26
59
|
}
|
|
@@ -22,3 +22,15 @@ export function totalExecutorCpuMs(stages
|
|
|
22
22
|
for (const s of stages) if (typeof s.executorCpuTime === 'number' && Number.isFinite(s.executorCpuTime) && s.executorCpuTime > 0) ns += s.executorCpuTime;
|
|
23
23
|
return ns > 0 ? nsToMs(ns) : null;
|
|
24
24
|
}
|
|
25
|
+
|
|
26
|
+
/** Summed output rows over the given stage attempts (see `withEarlierAttempts`). Like the other
|
|
27
|
+
* task-derived totals it is null until some attempt finished a task, and null when no stage
|
|
28
|
+
* recorded a row count, never 0. */
|
|
29
|
+
export function totalOutputRows(attempts ) {
|
|
30
|
+
if (!attempts.some((s) => (s.taskCount ?? 0) > 0)) return null;
|
|
31
|
+
let sum = 0, present = false;
|
|
32
|
+
for (const s of attempts) {
|
|
33
|
+
if (typeof s.outputRecords === 'number' && Number.isFinite(s.outputRecords)) { sum += s.outputRecords; present = true; }
|
|
34
|
+
}
|
|
35
|
+
return present ? sum : null;
|
|
36
|
+
}
|