mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-05 06:08:59 +00:00
Publish the 58 integrated S8 issues since beta.1. Synchronize versions, rebuild committed frontend assets, refresh ratchets to measured facts, and update release metadata. All 11 documentation screenshots were accepted as pixel-identical in WSL, without replacing PNG bytes. Owner-authorized manual ship review covers all 13 ship issues; High 0. Local checks: build/typecheck, 3510 unit tests passed (30 skipped), 20 selected browser smokes, Stage 3 dense observable contract. Full exact-SHA Validate remains mandatory before publication. Release: v1.79.0-beta.2 Issue: #694 Issue: #703 Issue: #704 Issue: #705 Issue: #707 Issue: #708 Issue: #712 Issue: #714 Issue: #715 Issue: #716 Issue: #717 Issue: #718 Issue: #719 Issue: #720 Issue: #721 Issue: #722 Issue: #723 Issue: #724 Issue: #725 Issue: #726 Issue: #727 Issue: #728 Issue: #729 Issue: #730 Issue: #731 Issue: #732 Issue: #733 Issue: #734 Issue: #735 Issue: #736 Issue: #737 Issue: #738 Issue: #739 Issue: #740 Issue: #741 Issue: #742 Issue: #743 Issue: #744 Issue: #745 Issue: #746 Issue: #747 Issue: #748 Issue: #749 Issue: #750 Issue: #751 Issue: #752 Issue: #753 Issue: #754 Issue: #755 Issue: #756 Issue: #757 Issue: #758 Issue: #759 Issue: #760 Issue: #761 Issue: #762 Issue: #772 Issue: #775 User-Visible: yes
145 lines
10 KiB
JavaScript
145 lines
10 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import { readFileSync } from 'node:fs';
|
|
|
|
// #425, заменяет #34. Декомпозиция фронтенда идёт попутно и продолжит идти, но
|
|
// два ядра всё равно прибавляют по 500–1000 строк за релиз: новое уезжает в
|
|
// новые модули, а из старых ничего не уходит. Проект «разложить всё по
|
|
// каталогам» не начался за 25 дней и не начнётся; вместо него — потолок,
|
|
// который делает рост осознанным.
|
|
//
|
|
// Правило простое: хочешь добавить в ядро — вынеси столько же. Число в дифе,
|
|
// решение в ревью.
|
|
|
|
// Мера — `split('\n').length`, то есть строки плюс завершающий перевод.
|
|
// Та же функция и для потолков, и для измерения: две разные меры разошлись бы
|
|
// на единицу, и гейт краснел бы на пустом месте (проверено при написании).
|
|
//
|
|
// #699 (решение владельца 2026-09-28): полоса вместо точки. Потолок —
|
|
// факт на последней бете; задача может вырасти над ним не больше чем на
|
|
// CORE_BAND строк, и уменьшение её не красит. Потолки опускает до факта
|
|
// релиз-менеджер раз в бету (`node scripts/ratchets.mjs tighten`): пока их
|
|
// правила каждая задача, два параллельных ядра конфликтовали на этих числах, а
|
|
// задача упиралась в потолок, потому что перед ней влили чужую (#689 после #691).
|
|
export const CORE_BAND = 50;
|
|
|
|
// Потолки. Меняются только вручную и только вместе с объяснением в ревью:
|
|
// потолок, который вычисляется от текущего размера, потолком не является.
|
|
// С #699 число — факт последней беты: его ставит `ratchets.mjs tighten` на
|
|
// кандидате, а строки ниже — история решений, а не расчёт текущего числа.
|
|
const CAPS = {
|
|
// #485 adds the View-side subscription/render integration seams; the live
|
|
// model and rendering themselves remain in dedicated modules.
|
|
// #500 moved config/layout identity and the adoption sequence into
|
|
// src/config-adoption.ts; the ratchet keeps that win.
|
|
// 2026-09-11, #534: +1 for `import { keyed }`. The line buys back the 80 ms
|
|
// that #525 put on every space switch, and there is nothing to move out —
|
|
// the render itself did not grow by a character.
|
|
// 2026-09-14, #564: the geometry/index/latch/DOM ownership implementation is
|
|
// isolated in device-hit-owner.ts. These 81 lines are the remaining card
|
|
// lifecycle invalidations and the presentation/action integration seams.
|
|
// 2026-09-23, #624: сняты 112 мёртвых делегатов и полей, которых не читает
|
|
// ни карточка, ни харнесс (реализация живёт в рантайме и зовётся оттуда),
|
|
// 190 неиспользуемых импортов и 9 мёртвых констант — 784 строки. Потолок
|
|
// опущен на выигрыш, запас над фактом три строки.
|
|
// 2026-09-24, #642: диалог «Оптимизировать планы» уехал в
|
|
// src/optimize-plans-dialog.ts — ушли пять делегатов, две стрелки-заглушки,
|
|
// поле фолбэка буфера обмена, дедуп dev-лога и литерал типа состояния,
|
|
// 62 строки. Потолок опущен на выигрыш, запас прежний.
|
|
// 2026-09-27, #676: +2 — вызов черновика лестницы в pointerdown сцены и
|
|
// рамка лестницы в верхнем оверлее (выше тел стен). Всё остальное слоя —
|
|
// жесты, рамка, магнит, диалог — живёт в stairs-editor.ts и stairs-box.ts.
|
|
'src/houseplan-card.ts': 12905,
|
|
// #478 removed the persisted room-draft editor branch. Keep that reduction.
|
|
// #485 keeps its large setup surface in editors/radar-section.ts; these are
|
|
// only the dialog state/save seam and the thin lazy-render adapter.
|
|
// 2026-09-18, #592: разметка четырёх диалогов настроек уехала в
|
|
// src/editors/{marker,space-settings,general-settings,room-settings}-dialog.ts
|
|
// — 1290 строк. Потолок опущен ровно на эту величину (14100 → 12810), запас
|
|
// над фактом остался прежним, три строки: выигрыш зафиксирован, иначе ядро
|
|
// отыграет его обратно первой же правкой диалога.
|
|
// 2026-09-23, #624: снесены мёртвые копии объявлений карточки (warm-boot,
|
|
// LS_*, GLOW_*, debounce, navigate, lruRead — 31 объявление и 6 типов) и
|
|
// 196 неиспользуемых импортов — 400 строк. Потолок опущен на выигрыш.
|
|
// 2026-09-24, #642: диалог «Оптимизировать планы» (превью, запуск,
|
|
// диагностика preflight, разметка) уехал в src/optimize-plans-dialog.ts за
|
|
// узкий порт из 18 членов — 362 строки. Потолок опущен на выигрыш.
|
|
'src/houseplan-editor-runtime.ts': 12032,
|
|
};
|
|
|
|
/**
|
|
* Храповик с полосой (#699): выше `cap + band` не пускает; выигрыш фиксирует
|
|
* бета, а не задача.
|
|
*
|
|
* Вторая половина храповика не исчезла, а переехала: без неё вынос двух тысяч
|
|
* строк ничего не изменит — потолок останется прежним, и ядро дорастёт до него
|
|
* обратно молча. Поэтому `tighten` на каждой бете опускает потолок до факта.
|
|
*/
|
|
export function coreBudgetViolations(sizes, caps, band = CORE_BAND) {
|
|
const problems = [];
|
|
for (const [file, cap] of Object.entries(caps)) {
|
|
const lines = sizes[file];
|
|
if (typeof lines !== 'number') {
|
|
problems.push({ file, kind: 'missing', text: `${file}: файл не измерен` });
|
|
continue;
|
|
}
|
|
if (lines > cap + band) {
|
|
problems.push({
|
|
file, kind: 'grew', over: lines - cap,
|
|
text: `${file}: ${lines} строк при потолке беты ${cap} — выросло на ${lines - cap}, больше полосы ${band}.`
|
|
+ ' Вынесите столько же в отдельный модуль либо поднимите потолок'
|
|
+ ' отдельным решением, объяснив его в ревью.',
|
|
});
|
|
}
|
|
}
|
|
return problems;
|
|
}
|
|
|
|
const measure = (file) => readFileSync(new URL(`../${file}`, import.meta.url), 'utf8').split('\n').length;
|
|
|
|
test('ядра не выросли выше потолка беты больше чем на полосу (#699)', () => {
|
|
const sizes = Object.fromEntries(Object.keys(CAPS).map((file) => [file, measure(file)]));
|
|
const problems = coreBudgetViolations(sizes, CAPS);
|
|
assert.deepEqual(problems.map((p) => p.text), [], problems.map((p) => p.text).join('\n'));
|
|
});
|
|
|
|
test('рост выше полосы становится нарушением с числом', () => {
|
|
const [problem] = coreBudgetViolations({ 'a.ts': 1300 }, { 'a.ts': 1000 });
|
|
assert.equal(problem.kind, 'grew');
|
|
assert.equal(problem.over, 300);
|
|
assert.match(problem.text, /выросло на 300, больше полосы 50/);
|
|
});
|
|
|
|
test('#699 уменьшение задачу не красит — потолок опускает бета', () => {
|
|
assert.deepEqual(coreBudgetViolations({ 'a.ts': 700 }, { 'a.ts': 1000 }), []);
|
|
assert.deepEqual(coreBudgetViolations({ 'a.ts': 1 }, { 'a.ts': 1000 }), []);
|
|
});
|
|
|
|
test('#699 рост в пределах полосы задачу не красит', () => {
|
|
assert.deepEqual(coreBudgetViolations({ 'a.ts': 1000 }, { 'a.ts': 1000 }), []);
|
|
assert.deepEqual(coreBudgetViolations({ 'a.ts': 1049 }, { 'a.ts': 1000 }), []);
|
|
});
|
|
|
|
test('#699 границы включительно: ровно потолок плюс полоса нарушением не считается', () => {
|
|
assert.equal(CORE_BAND, 50, 'полоса ядра — решение владельца 2026-09-28');
|
|
assert.deepEqual(coreBudgetViolations({ 'a.ts': 1050 }, { 'a.ts': 1000 }), []);
|
|
assert.equal(coreBudgetViolations({ 'a.ts': 1051 }, { 'a.ts': 1000 })[0].kind, 'grew');
|
|
});
|
|
|
|
test('потолки заданы для двух ядер и ни для чего больше', () => {
|
|
assert.deepEqual(Object.keys(CAPS).sort(),
|
|
['src/houseplan-card.ts', 'src/houseplan-editor-runtime.ts']);
|
|
});
|
|
|
|
test('потолки — числа в этом файле, а не вычисление от текущего размера', () => {
|
|
// AC4. Потолок, который считается от того, что сейчас на диске, разрешает
|
|
// любой рост и запрещает только уменьшение — то есть работает наоборот.
|
|
const source = readFileSync(new URL('./core-file-budget.test.mjs', import.meta.url), 'utf8');
|
|
const caps = source.slice(source.indexOf('const CAPS'), source.indexOf('};', source.indexOf('const CAPS')));
|
|
assert.match(caps, /'src\/houseplan-card\.ts': \d+/);
|
|
assert.doesNotMatch(caps, /measure|readFileSync|process\.env/);
|
|
for (const problem of coreBudgetViolations({ 'a.ts': 10 }, { 'a.ts': 10 })) {
|
|
assert.fail(`функция обязана принимать потолки аргументом: ${problem.text}`);
|
|
}
|
|
});
|