fix(performance): treat a counter/wall-clock type switch as a weakening

Turning `{ value: 100, slack: 10 }` into `{ value: 105, toleranceRatio: 1 }`
skipped the raised-counter-value rule and was reported as a lowered limit.
Switching an entry between counter and wall-clock now needs the
perf-baseline-increase label.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0166PWobUjpoiWt8E9bBdsCs
This commit is contained in:
Claude committed 2026-09-28 06:18:09 +00:00
1 parent e63173353d
commit 2079b59a66
3 files changed
+42 -2

No files matched your search

@@ -9,6 +9,8 @@
* or `value + slack`) went up, whose tolerance or slack widened, or that
* disappeared, is a failure. A counter's `value` may not go up either, even
* when narrower slack lowers its limit: the value is the measured evidence.
* Switching an entry between counter and wall-clock (adding or removing
* `toleranceRatio`) is a weakening too, so that rule cannot be sidestepped.
* New entries and lowered limits pass.
*
* `--allow-increase` turns those failures into printed "allowed" lines. CI
@@ -81,6 +83,8 @@ export function compareBaselineDirection({
);
continue;
}
const kind = (entry) =>
entry.toleranceRatio === undefined ? 'counter' : 'wall-clock';
const baseTolerance = baseEntry.toleranceRatio ?? 1;
const headTolerance = headEntry.toleranceRatio ?? 1;
const baseSlack = baseEntry.slack ?? 0;
@@ -91,6 +95,10 @@ export function compareBaselineDirection({
weakened.push(
`${label}: toleranceRatio widened from ${baseTolerance} to ${headTolerance}. Tolerances are a maintainer decision (the ${BASELINE_INCREASE_LABEL} label); a PR may only narrow them.`
);
} else if (kind(baseEntry) !== kind(headEntry)) {
weakened.push(
`${label}: changed from a ${kind(baseEntry)} entry to a ${kind(headEntry)} entry. The two are read from different summary sections and compared differently, so a type change is a maintainer decision (the ${BASELINE_INCREASE_LABEL} label).`
);
} else if (headSlack > baseSlack) {
weakened.push(
`${label}: slack widened from ${formatNumber(baseSlack)} to ${formatNumber(headSlack)}${unit}. Slack is a maintainer decision (the ${BASELINE_INCREASE_LABEL} label); a PR may only narrow it.`
@@ -213,6 +213,37 @@ test('a counter value raised behind narrower slack still fails', () => {
assert.equal(allowed.allowed.length, 1);
});
test('switching an entry between counter and wall-clock fails', () => {
const counterToWallClock = compareBaselineDirection({
base: file(100, { x: { value: 100, slack: 10 } }),
head: file(100, { x: { value: 105, toleranceRatio: 1 } }),
});
assert.equal(counterToWallClock.failures.length, 1);
assert.deepEqual(counterToWallClock.lowered, []);
assert.match(
counterToWallClock.failures[0],
/launch\/x: changed from a counter entry to a wall-clock entry/
);
const wallClockToCounter = compareBaselineDirection({
base: file(100, { x: { value: 100, toleranceRatio: 1.25 } }),
head: file(100, { x: { value: 90 } }),
});
assert.equal(wallClockToCounter.failures.length, 1);
assert.match(
wallClockToCounter.failures[0],
/changed from a wall-clock entry to a counter entry/
);
const allowed = compareBaselineDirection({
base: file(100, { x: { value: 100, slack: 10 } }),
head: file(100, { x: { value: 105, toleranceRatio: 1 } }),
allowIncrease: true,
});
assert.deepEqual(allowed.failures, []);
assert.equal(allowed.allowed.length, 1);
});
test('allowIncrease reports every weakening as allowed instead of failing', () => {
const result = compareBaselineDirection({
base: file(100, { cdTicks: { value: 5 } }),