refactor: remove persisted room drafts

Issue: #478
User-Visible: yes
This commit is contained in:
Matysh
2026-09-06 17:38:47 +03:00
parent f1f05198a5
commit 5ab41a7299
172 changed files with 21772 additions and 3910 deletions
+6 -1
View File
@@ -157,8 +157,13 @@ export const LOW_HEADROOM_WARNING_BYTES = 15_000;
* только планы с мебелью, редактор отдаёт его рантайму синхронно. Измеренный
* initial факт 289 690 Б оставляет 810 Б сверху и 1 190 Б до нижней границы
* полосы; запас до стены 301 066 — 11 376 Б.
*
* 2026-09-06, #478: потолок опущен 290 500 → 289 500 без изменения общего
* бюджета. Удаление persisted room-draft веток снизило initial факт до
* 288 571 Б: 929 Б сверху и 1 071 Б до нижней границы полосы. Экономия
* закреплена и не превращается в разрешение для незаметного роста.
*/
export const INITIAL_VIEW_GZIP_CEILING = 290_500;
export const INITIAL_VIEW_GZIP_CEILING = 289_500;
export const INITIAL_VIEW_CEILING_BAND = 2_000;
/**
+10 -68
View File
@@ -399,17 +399,6 @@ const MUTANT_DEFINITIONS = [
replace: ' if (false && !render) return;',
}],
},
{
id: 'draft-delete-drops-the-promise',
guard: 'node demo/smoke_free_walls.mjs',
because: 'a delayed confirmation must keep the draft deletion pending all the way to the '
+ 'card facade; dropping the runtime promise makes the smoke inspect stale geometry (#405)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: " if (sel.kind === 'draft') { await this._deleteDraftWhole(); return; }",
replace: " if (sel.kind === 'draft') { void this._deleteDraftWhole(); return; }",
}],
},
{
id: 'smoke-guard-blind-to-tail',
guard: 'node demo/guard/verify-guard.mjs',
@@ -2526,14 +2515,14 @@ const MUTANT_DEFINITIONS = [
+ 'through the generic full-space transaction recreates the measured one-second pause',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: " commitDraftSegmentGeometry(this, this.host._t('history.draft_segment'), before);",
replace: " this._commitPhysicalGeometry(this.host._t('history.draft_segment'), before);",
find: " if (!commitWallChainSegmentGeometry(this, this.host._t('history.wall_segment'), before)) {",
replace: " if (!this._commitPhysicalGeometry(this.host._t('history.wall_segment'), before)) {",
}],
},
{
id: 'wall-draw-local-neighbour-dropped',
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
+ '&& node --test --test-name-pattern="local draft projection" '
+ '&& node --test --test-name-pattern="local projection retains" '
+ 'test/draft-live-preflight.test.mjs',
because: 'a bounded proof that drops a room whose masonry envelope meets the new segment '
+ 'can accept geometry the generic barrier rejects (#461 AC4)',
@@ -2543,17 +2532,6 @@ const MUTANT_DEFINITIONS = [
replace: ' return [];',
}],
},
{
id: 'wall-draw-terminal-full-check-skipped',
guard: 'node demo/benchmark_wall_draw_click.mjs',
because: 'the local click verdict is deliberately non-terminal; finishing a wall chain must '
+ 'still cross an independent full-space barrier (#461 AC7)',
patches: [{
file: 'src/houseplan-editor-runtime.ts',
find: " this._commitPhysicalGeometry(this.host._t('history.wall_chain_finish'), before);",
replace: " this._recordGeometry(this.host._t('history.wall_chain_finish'), before);",
}],
},
{
id: 'wall-draw-rejection-rollback-skipped',
guard: 'node demo/smoke_wall_draw_click.mjs',
@@ -2573,8 +2551,8 @@ const MUTANT_DEFINITIONS = [
+ 'the junction pass; discarding it repays the expensive union on every click (#461 AC5)',
patches: [{
file: 'src/draft-live-commit.ts',
find: ' geometry, candidateProjection.roomIds,',
replace: ' null, candidateProjection.roomIds,',
find: ' localCandidate, localPrevious, before.spaceId, geometry, candidateProjection.roomIds,',
replace: ' localCandidate, localPrevious, before.spaceId, null, candidateProjection.roomIds,',
}],
},
{
@@ -3129,7 +3107,7 @@ const MUTANT_DEFINITIONS = [
+ '#234 потерял регресс (#241)',
patches: [{
file: 'scripts/smoke-links.mjs',
find: " symbols: ['chainSegmentCms', 'wallChainSegments', '_draftSegmentCms', '_closingWallCm'],",
find: " symbols: ['chainSegmentCms', 'wallChainSegments', '_wallChainSegmentCms', '_closingWallCm'],",
replace: ' symbols: [],',
}],
},
@@ -5029,29 +5007,6 @@ const MUTANT_DEFINITIONS = [
.map((poly: number[][]) => poly.map((p) => [p[0] / 1000, p[1] / 1000])),`,
}],
},
{
id: 'chain-merge-sees-own-draft',
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
because: 'завершаемая цепочка ещё лежит в room_drafts, и её собственные концы '
+ 'нельзя принимать за чужое примыкание — иначе стык с существующей стеной '
+ 'никогда не срастается (CODE-REVIEW-229-r1, High-2)',
patches: [{
file: 'src/wall-merge.ts',
find: ' if (exclude && draft?.id === exclude) return [];',
replace: ' void exclude;',
}],
},
{
id: 'partition-merge-disabled',
guard: 'node demo/smoke_wall_chain_merge.mjs',
because: 'без вызова слияния прямая, нарисованная в несколько кликов, снова хранится '
+ 'набором отрезков со швами на каждом стыке (#229)',
patches: [{
file: 'src/houseplan-card.ts',
find: ' this._mergeSpacePartitions(sp, drawnIds);',
replace: ' void drawnIds;',
}],
},
{
id: 'partition-merge-ignores-thickness',
guard: 'node --test --test-name-pattern="issue 229" test/wall-merge.test.mjs',
@@ -5549,28 +5504,15 @@ const MUTANT_DEFINITIONS = [
+ 'barrier would leave the authoritative catalogue behind the repaired projections (#282)',
patches: [{
file: 'src/plan-optimizer.ts',
find: ' wallSegmentsMigrated = commitWallSegmentModelInPlace(config).migratedSegments;',
replace: ' wallSegmentsMigrated = 0;',
find: ' const wallCommit = commitWallSegmentModelInPlace(config);',
replace: ' const wallCommit = { migratedSegments: 0, migratedDrafts: 0, migratedDraftSegments: 0 };',
}],
},
{
id: 'v8-draft-sanitation-shifts-segment-identity',
guard: 'npx tsc -p tsconfig.test.json && node scripts/fix-test-build.mjs '
+ '&& node --test --test-name-pattern="draft sanitation drops only" '
+ 'test/wall-segment-model.test.mjs',
because: 'skipping a duplicate adjacent point must drop its own zero edge instead of '
+ 'shifting the following model-v8 segment id onto the wrong carrier (#314)',
patches: [{
file: 'src/wall-segment-model.ts',
find: ' const source = draft.segments?.[index - 1];',
replace: ' const source = draft.segments?.[segments.length];',
}],
},
{
id: 'v8-rejected-physical-write-keeps-optimistic-draft',
id: 'current-rejected-physical-write-keeps-optimistic-wall',
guard: 'npm run bundle:sync && node demo/smoke_v8_draft_write.mjs',
because: 'a rejected config/set must synchronously discard its whole pending physical batch '
+ 'before the active draft can be promoted into a ghost partition (#314)',
+ 'before an optimistic active-chain partition survives as a ghost wall (#314/#478)',
patches: [{
file: 'src/houseplan-card.ts',
find: ' const rolledBack = this._rollbackRejectedPhysicalWrites(strictEntries);',
+2 -2
View File
@@ -357,11 +357,11 @@ export const SMOKE_LINKS = [
},
{
// #234: единый резолвер толщины отрезка цепочки. Смок перехода между
// толщинами не называет ни `chainSegmentCms`, ни `_draftSegmentCms` — он
// толщинами не называет ни `chainSegmentCms`, ни `_wallChainSegmentCms` — он
// рисует стены инструментом и проверяет, что кладка на стыке толщин
// остаётся связной. Общих с диффом символов у него ровно два, `_cellCm` и
// `_gridPitch`, и оба слишком широкие, чтобы что-то доказывать.
symbols: ['chainSegmentCms', 'wallChainSegments', '_draftSegmentCms', '_closingWallCm'],
symbols: ['chainSegmentCms', 'wallChainSegments', '_wallChainSegmentCms', '_closingWallCm'],
smokes: ['smoke_wall_thickness_transition.mjs'],
because: 'переход между двумя толщинами в одной цепочке: резолвер толщины '
+ 'отрезка решает, где кладка меняет глубину, а смок проверяет кладку, '
+1 -1
View File
@@ -180,7 +180,7 @@ export function selectSmokes(diffText, { root = repoRoot, table, corpus } = {})
// Одно распространённое имя — повод посмотреть, а не вывод. Сильной связь
// считается либо по двум и более совпадениям, либо по одному редкому символу:
// `_draftSegmentCms` есть в восьми смоках и сам по себе адресует контракт,
// `_wallChainSegmentCms` есть в нескольких смоках и сам адресует контракт,
// `_path` — в восемнадцати и адресует «здесь рисуют».
const rareLimit = Math.max(1, Math.floor(smokes.size * 0.05));
const direct = [];