fix: the clean-floor total is computed in per-room slices, not one long task

Moving the aggregate out of render fixed the first frame, but the work
itself was still one uninterrupted ~1.5 s task on the large-house
fixture — the interface stayed frozen, just a moment later, which is the
same symptom the issue reports. cleanFloorAreaSteps yields after every
room; the runtime advances it with an 8 ms budget per frame and
reschedules until it finishes, so no slice outlives a frame and the
skeletons stay until the number is ready.

The smoke now watches longtask entries for the whole show, not only the
first frame: a single long task while the values are computed fails it.

Issue: #509
User-Visible: no
This commit is contained in:
Codex
2026-09-10 11:31:37 +03:00
parent e2bb1e5390
commit 588ef42546
50 changed files with 445 additions and 362 deletions
+8 -1
View File
@@ -244,13 +244,20 @@ test('#509 AC1/AC2/AC9: значение показывает скелет до
? (values.deviceCount === null ? null : String(values.deviceCount)) : null),
representedHaDeviceIds: () => new Set(['d1', 'd2']),
totalCleanFloorAreaM2: () => 12.5,
// Порционный расчёт площади (#509): генератор, отдающий управление
// после каждой комнаты. Здесь — две порции, чтобы проверить и то, что
// незавершённый расчёт не считается готовым.
cleanFloorAreaSteps: function* steps() { yield; yield; return 12.5; },
};
assert.deepEqual(state(deviceCount), { kind: 'pending' });
// AC2: живая сущность отвечает сразу; отсутствующая — честная ошибка.
assert.deepEqual(state(entity), { kind: 'ready', text: 'On' });
assert.deepEqual(state({ ...entity, source: { type: 'entity', entity_id: 'light.gone' } }), { kind: 'unavailable' });
// Расчёт после кадра: имитируем его завершение.
// Порция короче полного расчёта не делает значение готовым…
assert.equal(runtime.advanceMetrics(-1), false, 'бюджет исчерпан — расчёт продолжится');
assert.equal(runtime.metricsFresh(), false);
// …а полный проход — делает.
runtime.computeMetrics();
assert.deepEqual(state(deviceCount), { kind: 'ready', text: '2' });