mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-02 12:49:56 +00:00
feat: add per-room temperature thresholds
Issue: #487 User-Visible: yes
This commit is contained in:
@@ -170,8 +170,14 @@ export const LOW_HEADROOM_WARNING_BYTES = 15_000;
|
||||
* 289 556 Б; writer, шрифт, печатная сцена и общий дизайнерский арт мебели
|
||||
* остались в `lazyPdfFiles` (114 486 Б gzip). Новый центр даёт 944 Б сверху и 1 056 Б
|
||||
* снизу; PDF-граф не пересекается с initial View.
|
||||
*
|
||||
* 2026-09-07, #487: потолок поднят 290 500 → 291 500 без изменения общего
|
||||
* бюджета. Pure-resolver диапазона комнаты и его вызовы нужны обоим View-
|
||||
* renderer'ам до загрузки редактора: именно они меняют температурную заливку
|
||||
* обычного и статичного плана. Измеренный факт 290 937 Б оставляет 563 Б
|
||||
* сверху и 1 437 Б до нижней границы полосы; UI и writer остались в lazy editor.
|
||||
*/
|
||||
export const INITIAL_VIEW_GZIP_CEILING = 290_500;
|
||||
export const INITIAL_VIEW_GZIP_CEILING = 291_500;
|
||||
export const INITIAL_VIEW_CEILING_BAND = 2_000;
|
||||
|
||||
/**
|
||||
|
||||
@@ -245,6 +245,34 @@ export const CONFIG_FIELD_REGISTRY = Object.freeze([
|
||||
migration: 'remove the fill token and materialize effective room glow on room edit or explicit optimization',
|
||||
compatibility: 'backend and frontend accept the legacy token indefinitely',
|
||||
},
|
||||
{
|
||||
id: 'spaces[].rooms[].settings.temp_min',
|
||||
selector: { path: ['spaces', '*', 'rooms', '*', 'settings', 'temp_min'] },
|
||||
storage: 'House Plan server config',
|
||||
type: 'finite number | null',
|
||||
default: 'unset/null (= inherit the lower comfort bound from the space)',
|
||||
level: 'room',
|
||||
ui: 'Room settings when the effective fill is Temperature',
|
||||
runtime: 'roomTempRangeOf; affects temperature floor fill and opening tunnel fill only',
|
||||
introduced: 'v1.73.0',
|
||||
status: 'current',
|
||||
migration: 'none — each absent/null bound inherits independently',
|
||||
compatibility: 'older clients ignore the field and may erase it when rewriting complete room settings',
|
||||
},
|
||||
{
|
||||
id: 'spaces[].rooms[].settings.temp_max',
|
||||
selector: { path: ['spaces', '*', 'rooms', '*', 'settings', 'temp_max'] },
|
||||
storage: 'House Plan server config',
|
||||
type: 'finite number | null',
|
||||
default: 'unset/null (= inherit the upper comfort bound from the space)',
|
||||
level: 'room',
|
||||
ui: 'Room settings when the effective fill is Temperature',
|
||||
runtime: 'roomTempRangeOf; affects temperature floor fill and opening tunnel fill only',
|
||||
introduced: 'v1.73.0',
|
||||
status: 'current',
|
||||
migration: 'none — each absent/null bound inherits independently',
|
||||
compatibility: 'older clients ignore the field and may erase it when rewriting complete room settings',
|
||||
},
|
||||
{
|
||||
id: 'spaces[].open_spans',
|
||||
selector: { path: ['spaces', '*', 'open_spans'] },
|
||||
|
||||
@@ -1186,6 +1186,14 @@
|
||||
"required": false,
|
||||
"type": "float"
|
||||
},
|
||||
"config.spaces[].rooms[].settings.temp_max": {
|
||||
"opaque": "<function _finite_number_or_none>",
|
||||
"required": false
|
||||
},
|
||||
"config.spaces[].rooms[].settings.temp_min": {
|
||||
"opaque": "<function _finite_number_or_none>",
|
||||
"required": false
|
||||
},
|
||||
"config.spaces[].rooms[].settings.temp_source": {
|
||||
"nullable": true,
|
||||
"required": false,
|
||||
|
||||
@@ -108,6 +108,28 @@ function relocateEditorPatch(patch, cardSource, editorSource) {
|
||||
// `find` обязан встречаться в файле ровно один раз: патч, который ложится «куда
|
||||
// попало», проверяет не то, что объявлен проверять. Это контролирует --check.
|
||||
const MUTANT_DEFINITIONS = [
|
||||
{
|
||||
id: 'room-temperature-blank-becomes-zero',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="room temperature draft" test/space-dialog.test.mjs',
|
||||
because: 'a blank per-room bound means inheritance and must never become the explicit numeric value zero',
|
||||
patches: [{
|
||||
file: 'src/space-dialog.ts',
|
||||
find: " if (String(raw ?? '').trim() === '') return { valid: true, value: null };",
|
||||
replace: " if (String(raw ?? '').trim() === '') return { valid: true, value: 0 };",
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'room-temperature-min-inherits-wrong-side',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
+ '&& node --test --test-name-pattern="room temperature range" test/logic.test.mjs',
|
||||
because: 'each absent room threshold must inherit the matching space side before the effective pair is normalized',
|
||||
patches: [{
|
||||
file: 'src/logic.ts',
|
||||
find: ' const rawMin = finiteOr(room?.settings?.temp_min, inheritedMin);',
|
||||
replace: ' const rawMin = finiteOr(room?.settings?.temp_min, inheritedMax);',
|
||||
}],
|
||||
},
|
||||
{
|
||||
id: 'pdf-shared-wall-twice',
|
||||
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
|
||||
@@ -2521,13 +2543,13 @@ const MUTANT_DEFINITIONS = [
|
||||
{
|
||||
id: 'schema-manifest-enum-drift',
|
||||
guard: 'node --test test/config-schema-parity.test.mjs',
|
||||
because: 'a backend enum value the frontend does not know (and the allow-list does not '
|
||||
+ 'bless) is exactly the schema drift #33 exists to catch — the manifest mutation '
|
||||
+ 'simulates the backend change without the frontend pair',
|
||||
because: 'a backend schema path the frontend does not know (and the allow-list does not '
|
||||
+ 'bless) is exactly the schema drift #33 exists to catch; a single-line path mutation '
|
||||
+ 'also stays deterministic across LF and CRLF schema dumps',
|
||||
patches: [{
|
||||
file: 'scripts/config-schema.json',
|
||||
find: " \"config.spaces[].settings.fill_mode\": {\n \"enum\": [\n \"custom\",",
|
||||
replace: " \"config.spaces[].settings.fill_mode\": {\n \"enum\": [\n \"phantom-33\",\n \"custom\",",
|
||||
find: ' "config.spaces[].settings.fill_mode": {',
|
||||
replace: ' "config.spaces[].settings.fill_mode_phantom": {',
|
||||
}],
|
||||
},
|
||||
{
|
||||
|
||||
@@ -27,6 +27,15 @@
|
||||
|
||||
/** @type {SmokeLink[]} */
|
||||
export const SMOKE_LINKS = [
|
||||
{
|
||||
symbols: [
|
||||
'roomTempRangeOf', 'roomTempRangeFromDraft', 'roomTempThresholdDraft',
|
||||
'applyRoomTempThresholdDraft', 'roomTemperatureControls',
|
||||
],
|
||||
smokes: ['smoke_room_temperature_thresholds.mjs'],
|
||||
because: 'the #487 production-bundle scenario proves partial inheritance, zero/invalid input, '
|
||||
+ 'hidden draft retention, reset and narrow-dialog overflow through the real room editor',
|
||||
},
|
||||
{
|
||||
symbols: [
|
||||
'PdfExportRuntime', 'buildPdfPage', 'writePdf', 'stableDimensionEdges',
|
||||
|
||||
Reference in New Issue
Block a user