diff --git a/demo/performance/README.md b/demo/performance/README.md index ea41b91c..5a0c8cf9 100644 --- a/demo/performance/README.md +++ b/demo/performance/README.md @@ -218,6 +218,17 @@ rationale in the change. Do not loosen a threshold merely to make a single red run pass. A new fixture profile gets a new profile id instead of silently changing the meaning of `large-house-v1`. +`large-house-isometric-v1` carries `countNoiseAllowance: 5` (the other +profiles keep 3). Owner decision 2026-09-09, #507: since v1.73.0-beta.1 the +isometric renderer lives in the lazy `iso-scene-render` chunk (#160 Stage 3), +so the single v1.72.0 boot task is split into two around that import. The +load-phase work is unchanged — timings, `longTask.totalP95Ms` and +`longTask.maxSingleMs` keep their unchanged ratios and still catch real +growth — but `longTask.countP95` counts the split as +2 tasks and, with +runner jitter, sat at 16 → 20 against a 19.2 limit on the v1.73.0 stable +comparison. The allowance widens the count check alone to 16 → 21 for that +baseline; it is not a licence for more work per task. + The `cleanFloor` entry ceiling is 100: the reviewed fixture warms exactly 100 deterministic room/physical-body entries. An extra 20 means that one complete floor was invalidated and rebuilt, so fixture extensions must recalibrate this diff --git a/demo/performance/budgets-large-house-isometric.json b/demo/performance/budgets-large-house-isometric.json index b69ca78b..668ae0fb 100644 --- a/demo/performance/budgets-large-house-isometric.json +++ b/demo/performance/budgets-large-house-isometric.json @@ -19,7 +19,7 @@ "maxSingleNoiseAllowanceMs": 250, "maxCountP95": 30, "maxCountRegressionRatio": 0.2, - "countNoiseAllowance": 3, + "countNoiseAllowance": 5, "maxTotalP95Ms": 12000, "maxTotalRegressionRatio": 0.2, "noiseAllowanceMs": 150 diff --git a/test/performance-budget.test.mjs b/test/performance-budget.test.mjs index a66b545a..6df294b0 100644 --- a/test/performance-budget.test.mjs +++ b/test/performance-budget.test.mjs @@ -256,3 +256,18 @@ test('interaction aggregate keeps hosted-runner headroom without weakening compo assert.equal(smoke.timings.cameraSeriesMs.hardMaxMs, 500); assert.equal(smoke.timings.editorSeriesMs.hardMaxMs, 750); }); + +test('isometric long-task count allowance covers the lazy iso-chunk split, nothing else (#507)', () => { + const isometric = readBudget('budgets-large-house-isometric.json'); + assert.equal(isometric.longTasks.countNoiseAllowance, 5, 'owner-accepted +2 tasks of the lazy iso-scene-render split plus jitter'); + assert.equal(isometric.longTasks.maxCountRegressionRatio, 0.2, 'the ratio is not the lever'); + assert.equal(isometric.longTasks.maxCountP95, 30); + assert.equal(isometric.longTasks.maxTotalRegressionRatio, 0.2, 'total work is still gated as before'); + assert.equal(isometric.longTasks.maxSingleRegressionRatio, 0.2); + for (const file of ['budgets.json', 'budgets-large-house-plan-snap.json', 'budgets-large-house-interaction.json']) { + assert.equal(readBudget(file).longTasks.countNoiseAllowance, 3, `${file} keeps the ordinary allowance`); + } + // The v1.73.0 stable comparison against v1.72.0: 16 → 20 passes, 22 does not. + const limit = Math.max(16 * (1 + isometric.longTasks.maxCountRegressionRatio), 16 + isometric.longTasks.countNoiseAllowance); + assert.equal(limit, 21); +});