sparkforensics-server 0.5.1 → 0.5.2
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/package.json +1 -1
- package/public/assets/{AutoscalingChurn-5hDGIXi4.js → AutoscalingChurn-8t3U3isq.js} +1 -1
- package/public/assets/{CacheUtilization-CT2SCnJJ.js → CacheUtilization-CJs9tTum.js} +1 -1
- package/public/assets/CachingOpportunity-D1NcHs0V.js +1 -0
- package/public/assets/{ColdStart-B38OiAOp.js → ColdStart-CdRJ9gD8.js} +1 -1
- package/public/assets/{ConfigAudit-BoplryCH.js → ConfigAudit-B5Gbe5js.js} +1 -1
- package/public/assets/CoreUsageArea-a--NTRGY.js +1 -0
- package/public/assets/{Dashboard-BgKodJl2.js → Dashboard-C1hNeX49.js} +2 -2
- package/public/assets/DisclosureContext-ZpE6CkHx.js +1 -0
- package/public/assets/{DuplicatePlanSubtree-BqS2A2j4.js → DuplicatePlanSubtree-dobXdz7E.js} +1 -1
- package/public/assets/{ExecutorUtilization-Dp52QGWo.js → ExecutorUtilization-D9grwi7t.js} +1 -1
- package/public/assets/{GcPressure-CT1yzR_s.js → GcPressure-8-G2ri10.js} +1 -1
- package/public/assets/{IncompleteRun-C7Qkjtjn.js → IncompleteRun-B91lky7a.js} +1 -1
- package/public/assets/{JobFailures-WHl3ELfh.js → JobFailures-BsWvBMyJ.js} +1 -1
- package/public/assets/{MemoryUtilization-D8IUDHJI.js → MemoryUtilization-BM5schZI.js} +1 -1
- package/public/assets/{OverBroadcast-6oSSAQ_R.js → OverBroadcast-DdN8JIJH.js} +1 -1
- package/public/assets/{PartitionSizing-BwdFL-mw.js → PartitionSizing-CY5HDYtp.js} +1 -1
- package/public/assets/{PlanExplorer-DcxmiQWL.js → PlanExplorer-DgHCDBD_.js} +1 -1
- package/public/assets/PlanGraphRoute-DH3KJb8j.js +1 -0
- package/public/assets/{RetryWaste-BTbeHkJc.js → RetryWaste-DOnE9vGF.js} +1 -1
- package/public/assets/{ShuffleIO-CRhrYNE0.js → ShuffleIO-MMnDESkF.js} +1 -1
- package/public/assets/{Skew-DSNXRG9V.js → Skew-BmZZJ5ms.js} +1 -1
- package/public/assets/{SlowHost-B7Lwu2EU.js → SlowHost-CsJzfEqo.js} +1 -1
- package/public/assets/{SmallFiles-C082c2rd.js → SmallFiles-BoK3R1Ex.js} +1 -1
- package/public/assets/{SpeculationWaste-BS2vpadr.js → SpeculationWaste-CnVxB5AJ.js} +1 -1
- package/public/assets/Spill-BhNicyBy.js +1 -0
- package/public/assets/{StageFailed-D3ac9Sou.js → StageFailed-mAhHU4l_.js} +1 -1
- package/public/assets/StageFindingGroup-BEtPWcT0.js +1 -0
- package/public/assets/{StageHeader-pI1nTwVf.js → StageHeader-DJkYkrsU.js} +1 -1
- package/public/assets/{StageShape-eO5le8iG.js → StageShape-BDxRknLp.js} +1 -1
- package/public/assets/{StageSlowness-BaNyfNvL.js → StageSlowness-BPRw-otN.js} +1 -1
- package/public/assets/{Straggler-D5Fnok_y.js → Straggler-CZCbnOWP.js} +1 -1
- package/public/assets/{TaskFailures-BWnC-K_G.js → TaskFailures-C57YcLFQ.js} +1 -1
- package/public/assets/{TinyTask-8_5lpq_2.js → TinyTask-Bi84qU7n.js} +1 -1
- package/public/assets/{UnderBroadcast-DJ0XSwth.js → UnderBroadcast-DdQV7htE.js} +1 -1
- package/public/assets/{finding-anchor-Cys8Z6Yn.js → finding-anchor-Cl6_5hfV.js} +1 -1
- package/public/assets/{impact-sort-BTQndbof.js → impact-sort-CssZ6MT2.js} +1 -1
- package/public/assets/index-2h_TgUAb.css +2 -0
- package/public/assets/index-B-03mG7K.js +14 -0
- package/public/assets/{parser-worker-DmeCnLWU.js → parser-worker-CA5RxqKc.js} +8 -8
- package/public/assets/{select-DIYN6D3y.js → select-CQjNhprm.js} +1 -1
- package/public/assets/{usePagedRows-BxvdFnPk.js → usePagedRows-Dyl6T8Ok.js} +1 -1
- package/public/assets/useRecentFiles-XZEnLlal.js +11 -0
- package/public/assets/{useSortMode-B8SRfAoG.js → useSortMode-Dhvit8dt.js} +1 -1
- package/public/docs/404.html +2 -2
- package/public/docs/assets/{app.D2GqAkhy.js → app.eYTPqTeq.js} +1 -1
- package/public/docs/assets/chunks/@localSearchIndexroot.u_e5bQz4.js +1 -0
- package/public/docs/assets/chunks/{VPLocalSearchBox.BS4cSmtW.js → VPLocalSearchBox.DsZrQKQR.js} +1 -1
- package/public/docs/assets/chunks/{theme.BuxVpb0H.js → theme.DsTNE2pE.js} +2 -2
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.js +1 -0
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.js +1 -0
- package/public/docs/assets/{contributor-guide_architecture_state-and-history_run-comparison-internals.md.uuAKpY0Y.lean.js → contributor-guide_architecture_state-and-history_run-comparison-internals.md.CZA0JLtV.lean.js} +1 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.js +1 -0
- package/public/docs/assets/{user-guide_getting-started_ci-and-automation.md.DpnfKz3x.js → user-guide_getting-started_ci-and-automation.md.OUQqw3mI.js} +5 -4
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.OUQqw3mI.lean.js +1 -0
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.CPowlb2q.js → user-guide_mcp-tools_compare-runs.md.Cc_gLoix.js} +3 -2
- package/public/docs/assets/{user-guide_mcp-tools_compare-runs.md.CPowlb2q.lean.js → user-guide_mcp-tools_compare-runs.md.Cc_gLoix.lean.js} +1 -1
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.Dq5Azk8G.js → user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.js} +2 -2
- package/public/docs/assets/{user-guide_mcp-tools_evaluate-budgets.md.Dq5Azk8G.lean.js → user-guide_mcp-tools_evaluate-budgets.md.BB0nDY3Z.lean.js} +1 -1
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.js +1 -0
- package/public/docs/assets/user-guide_run-comparison.md.BUALkohi.lean.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.js +1 -0
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.DSXGu2tA.lean.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.js +1 -0
- package/public/docs/assets/user-guide_understanding-findings.md.C9YRruMT.lean.js +1 -0
- package/public/docs/contributor-guide/architecture/board-widgets/caching-and-memory.html +3 -3
- package/public/docs/contributor-guide/architecture/board-widgets/plan-advisor.html +3 -3
- package/public/docs/contributor-guide/architecture/board-widgets/visual-system-and-templating.html +3 -3
- package/public/docs/contributor-guide/architecture/board-widgets.html +3 -3
- package/public/docs/contributor-guide/architecture/detector-contract/plan-attribution.html +3 -3
- package/public/docs/contributor-guide/architecture/detector-contract/threshold-tables.html +5 -5
- package/public/docs/contributor-guide/architecture/detector-contract.html +3 -3
- package/public/docs/contributor-guide/architecture/drill-down/plan-graph.html +3 -3
- package/public/docs/contributor-guide/architecture/drill-down.html +3 -3
- package/public/docs/contributor-guide/architecture/impact-estimation/caveats-tuning-and-coverage.html +3 -3
- package/public/docs/contributor-guide/architecture/impact-estimation/stage-union-rollup.html +3 -3
- package/public/docs/contributor-guide/architecture/impact-estimation.html +3 -3
- package/public/docs/contributor-guide/architecture/index.html +3 -3
- package/public/docs/contributor-guide/architecture/overview.html +3 -3
- package/public/docs/contributor-guide/architecture/state-and-history/history-server-intake.html +3 -3
- package/public/docs/contributor-guide/architecture/state-and-history/run-comparison-internals.html +5 -5
- package/public/docs/contributor-guide/architecture/state-and-history.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering/findings-tab.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering/investigation-routing.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering/list-sort-mode.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering/reference-section.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering/row-expand-contract.html +3 -3
- package/public/docs/contributor-guide/architecture/widget-rendering.html +3 -3
- package/public/docs/contributor-guide/architecture/worker-protocol/cli-and-mcp.html +5 -5
- package/public/docs/contributor-guide/architecture/worker-protocol/core-and-event-validation.html +3 -3
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-availability.html +3 -3
- package/public/docs/contributor-guide/architecture/worker-protocol/evidence-report.html +3 -3
- package/public/docs/contributor-guide/architecture/worker-protocol.html +3 -3
- package/public/docs/contributor-guide/contributing.html +3 -3
- package/public/docs/contributor-guide/development-setup.html +3 -3
- package/public/docs/contributor-guide/testing.html +3 -3
- package/public/docs/hashmap.json +1 -1
- package/public/docs/index.html +3 -3
- package/public/docs/tuning-reference/anti-patterns.html +3 -3
- package/public/docs/tuning-reference/aqe.html +3 -3
- package/public/docs/tuning-reference/bottleneck-broadcast-sizing.html +3 -3
- package/public/docs/tuning-reference/bottleneck-cold-start.html +3 -3
- package/public/docs/tuning-reference/bottleneck-duplicate-plan-subtree.html +3 -3
- package/public/docs/tuning-reference/bottleneck-failures.html +3 -3
- package/public/docs/tuning-reference/bottleneck-gc.html +3 -3
- package/public/docs/tuning-reference/bottleneck-job-failure-rate.html +3 -3
- package/public/docs/tuning-reference/bottleneck-memory-utilization.html +3 -3
- package/public/docs/tuning-reference/bottleneck-retry-waste.html +3 -3
- package/public/docs/tuning-reference/bottleneck-shuffle.html +3 -3
- package/public/docs/tuning-reference/bottleneck-skew.html +3 -3
- package/public/docs/tuning-reference/bottleneck-slow-host.html +3 -3
- package/public/docs/tuning-reference/bottleneck-small-files.html +3 -3
- package/public/docs/tuning-reference/bottleneck-spill.html +3 -3
- package/public/docs/tuning-reference/bottleneck-straggler.html +3 -3
- package/public/docs/tuning-reference/bottleneck-tiny-tasks.html +3 -3
- package/public/docs/tuning-reference/bottleneck-utilization.html +3 -3
- package/public/docs/tuning-reference/caching.html +3 -3
- package/public/docs/tuning-reference/cluster-config.html +3 -3
- package/public/docs/tuning-reference/config.html +3 -3
- package/public/docs/tuning-reference/data-formats.html +3 -3
- package/public/docs/tuning-reference/index.html +3 -3
- package/public/docs/tuning-reference/intro.html +3 -3
- package/public/docs/tuning-reference/joins.html +3 -3
- package/public/docs/tuning-reference/memory-model.html +3 -3
- package/public/docs/tuning-reference/metrics.html +3 -3
- package/public/docs/tuning-reference/partitioning.html +3 -3
- package/public/docs/tuning-reference/pyspark.html +3 -3
- package/public/docs/tuning-reference/shuffle.html +3 -3
- package/public/docs/tuning-reference/spark-architecture.html +3 -3
- package/public/docs/tuning-reference/table-formats.html +3 -3
- package/public/docs/user-guide/alternative-log-retrieval/managed-platforms.html +3 -3
- package/public/docs/user-guide/alternative-log-retrieval/ssh-bastion.html +3 -3
- package/public/docs/user-guide/alternative-log-retrieval.html +3 -3
- package/public/docs/user-guide/getting-started/ci-and-automation.html +8 -7
- package/public/docs/user-guide/getting-started/reading-the-dashboard.html +3 -3
- package/public/docs/user-guide/getting-started/regression-metric-keys.html +3 -3
- package/public/docs/user-guide/getting-started/tuning-thresholds.html +3 -3
- package/public/docs/user-guide/getting-started.html +3 -3
- package/public/docs/user-guide/mcp-tools/compare-runs.html +7 -6
- package/public/docs/user-guide/mcp-tools/diagnose-run.html +3 -3
- package/public/docs/user-guide/mcp-tools/evaluate-budgets.html +5 -5
- package/public/docs/user-guide/mcp-tools/get-finding-documentation.html +3 -3
- package/public/docs/user-guide/mcp-tools/get-finding-evidence.html +3 -3
- package/public/docs/user-guide/mcp-tools/get-reference-doc.html +3 -3
- package/public/docs/user-guide/mcp-tools/get-run-summary.html +3 -3
- package/public/docs/user-guide/mcp-tools/list-runs.html +3 -3
- package/public/docs/user-guide/mcp-tools.html +3 -3
- package/public/docs/user-guide/run-comparison/how-stages-are-matched.html +5 -5
- package/public/docs/user-guide/run-comparison.html +5 -5
- package/public/docs/user-guide/understanding-findings.html +5 -5
- package/public/export-template.html +3 -3
- package/public/index.html +3 -3
- package/vendor-core/cli/budgets.js +62 -2
- package/vendor-core/cli/regression-budgets.js +35 -0
- package/vendor-core/comparison-output.js +2 -1
- package/vendor-core/core-source-hash.txt +1 -1
- package/vendor-core/detectors.js +219 -56
- package/vendor-core/docs-content/detection/chrn.md +3 -1
- package/vendor-core/docs-content/detection/cold.md +2 -1
- package/vendor-core/docs-content/detection/plan.md +9 -2
- package/vendor-core/docs-content/detection/shfl.md +8 -2
- package/vendor-core/docs-content/detection/skew.md +11 -5
- package/vendor-core/docs-content/detection/slow.md +6 -2
- package/vendor-core/docs-content/detection/spill.md +4 -1
- package/vendor-core/docs-content/detection/strag.md +5 -3
- package/vendor-core/docs-content/detection/tiny.md +3 -2
- package/vendor-core/evidence-report.js +11 -11
- package/vendor-core/finding-presentation.js +39 -13
- package/vendor-core/finding-types.js +50 -6
- package/vendor-core/mcp-server-factory.js +6 -2
- package/vendor-core/mcp-tools.js +10 -1
- package/vendor-core/median.js +8 -0
- package/vendor-core/run-comparison.js +2 -0
- package/vendor-core/sequence-alignment.js +83 -0
- package/vendor-core/stage-alignment.js +387 -63
- package/vendor-core/stage-quantiles.js +3 -1
- package/vendor-core/stage-structure.js +83 -0
- package/public/assets/CachingOpportunity-D_O_WkbH.js +0 -1
- package/public/assets/CoreUsageArea-csgwNxkl.js +0 -1
- package/public/assets/DisclosureContext-B0siMVdg.js +0 -1
- package/public/assets/PlanGraphRoute-pqnHTt4i.js +0 -1
- package/public/assets/Spill-B4DVKHXx.js +0 -1
- package/public/assets/StageFindingGroup-D9naK109.js +0 -1
- package/public/assets/index-BcqTLKFp.css +0 -2
- package/public/assets/index-DCeWge12.js +0 -13
- package/public/assets/useRecentFiles-C3Ov47U7.js +0 -11
- package/public/docs/assets/chunks/@localSearchIndexroot.D4OdkQjy.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_detector-contract_threshold-tables.md.fkPBXsU2.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_state-and-history_run-comparison-internals.md.uuAKpY0Y.js +0 -1
- package/public/docs/assets/contributor-guide_architecture_worker-protocol_cli-and-mcp.md.Dk08VS7n.js +0 -1
- package/public/docs/assets/user-guide_getting-started_ci-and-automation.md.DpnfKz3x.lean.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.B6aNtDYF.js +0 -1
- package/public/docs/assets/user-guide_run-comparison.md.B6aNtDYF.lean.js +0 -1
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.XBzQ1oEU.js +0 -1
- package/public/docs/assets/user-guide_run-comparison_how-stages-are-matched.md.XBzQ1oEU.lean.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.Dqt2H_C1.js +0 -1
- package/public/docs/assets/user-guide_understanding-findings.md.Dqt2H_C1.lean.js +0 -1
- /package/public/docs/assets/{contributor-guide_architecture_detector-contract_threshold-tables.md.fkPBXsU2.lean.js → contributor-guide_architecture_detector-contract_threshold-tables.md.CKjWG56Y.lean.js} +0 -0
- /package/public/docs/assets/{contributor-guide_architecture_worker-protocol_cli-and-mcp.md.Dk08VS7n.lean.js → contributor-guide_architecture_worker-protocol_cli-and-mcp.md.DC1YqXBp.lean.js} +0 -0
package/public/index.html
CHANGED
|
@@ -23,14 +23,14 @@
|
|
|
23
23
|
document.documentElement.setAttribute('data-theme', 'light');
|
|
24
24
|
} catch (_) {}
|
|
25
25
|
</script>
|
|
26
|
-
<script type="module" crossorigin src="./assets/index-
|
|
26
|
+
<script type="module" crossorigin src="./assets/index-B-03mG7K.js"></script>
|
|
27
27
|
<link rel="modulepreload" crossorigin href="./assets/rolldown-runtime-hePW80VL.js">
|
|
28
28
|
<link rel="modulepreload" crossorigin href="./assets/charts-vendor-0VMaLVLN.js">
|
|
29
29
|
<link rel="modulepreload" crossorigin href="./assets/plan-graph-vendor-BYl-AzN5.js">
|
|
30
30
|
<link rel="modulepreload" crossorigin href="./assets/react-vendor-DEdfrRTJ.js">
|
|
31
|
-
<link rel="modulepreload" crossorigin href="./assets/DisclosureContext-
|
|
31
|
+
<link rel="modulepreload" crossorigin href="./assets/DisclosureContext-ZpE6CkHx.js">
|
|
32
32
|
<link rel="stylesheet" crossorigin href="./assets/plan-graph-vendor-DLioOiRN.css">
|
|
33
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
33
|
+
<link rel="stylesheet" crossorigin href="./assets/index-2h_TgUAb.css">
|
|
34
34
|
</head>
|
|
35
35
|
<body>
|
|
36
36
|
<div id="root"></div>
|
|
@@ -3,6 +3,7 @@ import { computeSkewRatio, ENTRY_BY_TYPE, } from '../det
|
|
|
3
3
|
import { effectiveThresholds } from '../threshold-overrides.js';
|
|
4
4
|
import { IMPACT_BAND_ORDER } from '../format-utils.js';
|
|
5
5
|
|
|
6
|
+
import { PAIR_DELTA_METRICS, } from '../stage-alignment.js';
|
|
6
7
|
|
|
7
8
|
|
|
8
9
|
|
|
@@ -14,13 +15,23 @@ const IMPACT_BANDS = Object.keys(IMPACT_BAND_ORDER) ;
|
|
|
14
15
|
|
|
15
16
|
|
|
16
17
|
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
17
23
|
|
|
24
|
+
|
|
25
|
+
export const STAGE_QUALITIES = ['exact', 'structural', 'aligned'];
|
|
26
|
+
export const DEFAULT_STAGE_BUDGET_QUALITIES = ['exact', 'structural'];
|
|
27
|
+
/** Metrics with a regression direction (higher is worse). Input and output volume are workload, not performance. */
|
|
28
|
+
export const NEUTRAL_PAIR_METRICS = new Set(['inputBytes', 'outputBytes']);
|
|
18
29
|
|
|
19
30
|
|
|
20
|
-
|
|
31
|
+
|
|
21
32
|
|
|
22
33
|
|
|
23
|
-
|
|
34
|
+
|
|
24
35
|
|
|
25
36
|
|
|
26
37
|
|
|
@@ -146,6 +157,50 @@ function checkRegression(comparison , maxRegressionPct
|
|
|
146
157
|
: { name: 'max-regression', metric: regressionMetric, status: 'pass', detail: `Metric "${regressionMetric}" ${pctLabel}, within budget ${maxRegressionPct}%.` };
|
|
147
158
|
}
|
|
148
159
|
|
|
160
|
+
function checkStageRegression(
|
|
161
|
+
comparison , { metric, maxPct } , qualities ,
|
|
162
|
+
) {
|
|
163
|
+
const name = 'max-stage-regression' ;
|
|
164
|
+
if (!(PAIR_DELTA_METRICS ).includes(metric)) {
|
|
165
|
+
return { name, metric, status: 'inconclusive', detail: `Metric "${metric}" is not a paired-stage metric (expected one of: ${PAIR_DELTA_METRICS.join(', ')}).` };
|
|
166
|
+
}
|
|
167
|
+
if (NEUTRAL_PAIR_METRICS.has(metric)) {
|
|
168
|
+
return { name, metric, status: 'inconclusive', detail: `Metric "${metric}" measures workload volume, not performance: it has no regression direction to check.` };
|
|
169
|
+
}
|
|
170
|
+
const eligible = comparison.stagePairs.filter((p) => qualities.includes(p.quality));
|
|
171
|
+
if (eligible.length === 0) {
|
|
172
|
+
return { name, metric, status: 'inconclusive', detail: comparison.stagePairs.length === 0
|
|
173
|
+
? 'No stages were paired between the two runs.'
|
|
174
|
+
: `None of the ${comparison.stagePairs.length} paired stage(s) has quality ${qualities.join(' or ')}.` };
|
|
175
|
+
}
|
|
176
|
+
const measured = eligible
|
|
177
|
+
.map((pair) => ({ pair, delta: pair.deltas[metric ] }))
|
|
178
|
+
.filter(({ delta }) => delta.baseline != null && delta.delta != null);
|
|
179
|
+
if (measured.length === 0) {
|
|
180
|
+
return { name, metric, status: 'inconclusive', detail: `Metric "${metric}" is unavailable for every eligible paired stage.` };
|
|
181
|
+
}
|
|
182
|
+
const regressions = measured
|
|
183
|
+
.filter(({ delta }) => delta.delta > 0)
|
|
184
|
+
.map(({ pair, delta }) => ({ pair, delta, pct: delta.baseline === 0 ? Infinity : (delta.delta / delta.baseline ) * 100 }))
|
|
185
|
+
.sort((a, b) => b.pct - a.pct || a.pair.pairId.localeCompare(b.pair.pairId));
|
|
186
|
+
const over = regressions.filter((r) => r.pct > maxPct);
|
|
187
|
+
const scope = `${measured.length} paired stage(s)`;
|
|
188
|
+
if (over.length === 0) {
|
|
189
|
+
const worst = regressions[0];
|
|
190
|
+
return { name, metric, status: 'pass', detail: worst
|
|
191
|
+
? `No paired stage regressed "${metric}" beyond ${maxPct}% across ${scope}; the largest was ${formatPct(worst.pct)} (pair ${worst.pair.pairId}).`
|
|
192
|
+
: `No paired stage regressed "${metric}" across ${scope}.` };
|
|
193
|
+
}
|
|
194
|
+
const listed = over.slice(0, 3).map((r) => `pair ${r.pair.pairId} (${r.pair.quality}) ${formatPct(r.pct)}`).join(', ');
|
|
195
|
+
const more = over.length > 3 ? `, and ${over.length - 3} more` : '';
|
|
196
|
+
return { name, metric, status: 'violation',
|
|
197
|
+
detail: `${over.length} of ${scope} regressed "${metric}" beyond ${maxPct}%: ${listed}${more}.` };
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function formatPct(pct ) {
|
|
201
|
+
return pct === Infinity ? 'from 0' : `+${pct.toFixed(1)}%`;
|
|
202
|
+
}
|
|
203
|
+
|
|
149
204
|
function checkFailOnIntroduced(comparison , band ) {
|
|
150
205
|
if (band !== 'all' && !IMPACT_BANDS.includes(band )) {
|
|
151
206
|
return { name: 'fail-on-introduced', status: 'inconclusive', detail: `Impact band "${band}" is not recognized (expected "all" or one of ${IMPACT_BANDS.join(', ')}).` };
|
|
@@ -198,6 +253,11 @@ export function evaluateBudgets({ appModel, catalog, budgets, comparison, thresh
|
|
|
198
253
|
for (const { metric, maxPct } of budgets.regressionBudgets ?? []) {
|
|
199
254
|
pushComparisonBudget(results, comparison, 'max-regression', (c) => checkRegression(c, maxPct, metric), metric);
|
|
200
255
|
}
|
|
256
|
+
const stageQualities = budgets.stageQualities ?? DEFAULT_STAGE_BUDGET_QUALITIES;
|
|
257
|
+
for (const budget of budgets.stageRegressionBudgets ?? []) {
|
|
258
|
+
pushComparisonBudget(results, comparison, 'max-stage-regression',
|
|
259
|
+
(c) => checkStageRegression(c, budget, stageQualities), budget.metric);
|
|
260
|
+
}
|
|
201
261
|
if (budgets.failOnIntroduced !== undefined) {
|
|
202
262
|
pushComparisonBudget(results, comparison, 'fail-on-introduced',
|
|
203
263
|
(c) => checkFailOnIntroduced(c, budgets.failOnIntroduced ));
|
|
@@ -4,6 +4,9 @@
|
|
|
4
4
|
import { readFileSync } from 'node:fs';
|
|
5
5
|
import { resolve } from 'node:path';
|
|
6
6
|
import { COMPARISON_METRIC_KEYS } from '../run-comparison.js';
|
|
7
|
+
import { PAIR_DELTA_METRICS } from '../stage-alignment.js';
|
|
8
|
+
import { NEUTRAL_PAIR_METRICS, STAGE_QUALITIES } from './budgets.js';
|
|
9
|
+
|
|
7
10
|
|
|
8
11
|
|
|
9
12
|
|
|
@@ -81,3 +84,35 @@ export function combineRegressionBudgets(sources )
|
|
|
81
84
|
}
|
|
82
85
|
return sources.map((s) => s.budget);
|
|
83
86
|
}
|
|
87
|
+
|
|
88
|
+
/** Refuses a stage budget metric that is not a paired-stage metric or has no regression direction. */
|
|
89
|
+
export function assertStageBudgetMetric(metric , origin ) {
|
|
90
|
+
if (!(PAIR_DELTA_METRICS ).includes(metric)) {
|
|
91
|
+
throw new Error(`${origin}: unknown paired-stage metric "${metric}" (expected one of: ${PAIR_DELTA_METRICS.filter((m) => !NEUTRAL_PAIR_METRICS.has(m)).join(', ')}).`);
|
|
92
|
+
}
|
|
93
|
+
if (NEUTRAL_PAIR_METRICS.has(metric)) {
|
|
94
|
+
throw new Error(`${origin}: "${metric}" measures workload volume, not performance, so it has no regression direction to budget.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** One `--stage-regression-budget` value, `<metric>:<pct>`, over the paired-stage metrics. */
|
|
99
|
+
export function parseStageRegressionBudgetFlag(spec ) {
|
|
100
|
+
const origin = `--stage-regression-budget "${spec}"`;
|
|
101
|
+
const colon = spec.indexOf(':');
|
|
102
|
+
if (colon === -1) throw new Error(`${origin}: expected <metric>:<pct>.`);
|
|
103
|
+
const metric = spec.slice(0, colon);
|
|
104
|
+
const pct = spec.slice(colon + 1);
|
|
105
|
+
assertStageBudgetMetric(metric, origin);
|
|
106
|
+
if (!PCT_PATTERN.test(pct)) throw new Error(`${origin}: "${pct}" is not a non-negative percentage.`);
|
|
107
|
+
return { metric, maxPct: Number(pct) };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** The pair qualities a stage budget reads, from a comma list such as `exact,structural`. */
|
|
111
|
+
export function parseStageQualities(list , origin ) {
|
|
112
|
+
const qualities = list.split(',').map((q) => q.trim()).filter(Boolean);
|
|
113
|
+
const bad = qualities.find((q) => !(STAGE_QUALITIES ).includes(q));
|
|
114
|
+
if (qualities.length === 0 || bad !== undefined) {
|
|
115
|
+
throw new Error(`${origin}: ${bad === undefined ? 'no quality given' : `unknown quality "${bad}"`} (expected a list from: ${STAGE_QUALITIES.join(', ')}).`);
|
|
116
|
+
}
|
|
117
|
+
return qualities ;
|
|
118
|
+
}
|
|
@@ -11,7 +11,7 @@ import { redactComparison } from './redact.js';
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
|
|
16
16
|
|
|
17
17
|
/** `full` carries every field (the CLI); `summary` leaves out `stagePairs` (MCP, which returns them
|
|
@@ -33,6 +33,7 @@ export function comparisonOutput(comparison , view
|
|
|
33
33
|
unmatched: comparison.unmatched,
|
|
34
34
|
replanned: comparison.replanned,
|
|
35
35
|
bookkeepingStageIds: comparison.bookkeepingStageIds,
|
|
36
|
+
executionAlignment: comparison.executionAlignment,
|
|
36
37
|
};
|
|
37
38
|
}
|
|
38
39
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
|
|
1
|
+
7aaca3af812e0e5a4f4632ad7577fc438b589520a27422ce8c986b156de82260
|