Skip to content

feat(undo): byte budget, meta-only eviction, compaction (PR11 part 1) - #292

Merged
barakbl merged 2 commits into
mainfrom
feat/undo-tiled-eviction
Jul 16, 2026
Merged

feat(undo): byte budget, meta-only eviction, compaction (PR11 part 1)#292
barakbl merged 2 commits into
mainfrom
feat/undo-tiled-eviction

Conversation

@barakbl

@barakbl barakbl commented Jul 16, 2026

Copy link
Copy Markdown
Owner

First of two parts for PR11 (bounding the tile-undo delta chain). This part replaces PR10's eager fold-into-base with the plan's deferred foldedIds model + byte budget + compaction. Part 2 adds QuotaExceededError recovery + the one-time toast. On-mode only; flag off is unchanged.

What's in it

  • Meta-only eviction - TileShadow moves the oldest active entries into a folded list (no pixel work) while the window exceeds MAX_UNDO or the byte budget = min(32MB, storage.estimate().quota / 20) (sized at boot via applyBudget). Keeps ≥1 active entry, so a user at the stack bottom overshoots transiently rather than losing the entry they just made. After a commit the pointer is at the tip, so eviction only folds entries strictly below it (pointer remaps as it folds).

  • Compaction - once folded passes 30, one enqueued step bakes every folded entry into the base and bumps the base version; the store rewrites the base and deletes the folded rows in the same tx (never folded rows without a base).

  • Reconstruction / serialize / hydrate apply base + folded + active, so boot replays folded rows and stays exact across a compaction boundary.

  • Store - meta2 gains foldedIds; folded + active share one entry:<id> namespace tracked by savedRowIds. A pre-PR11 meta2 (no foldedIds) still loads with an empty folded list, so on-mode early sessions don't drop to the v1 ladder.

Acceptance

  • fold / pointer remap, undo-redo-after-eviction - unit tests reconstruct exactly within the active window after eviction.
  • byte-budget eviction - a 1-byte budget folds down to the kept entry; a 4KB-budget 500-stroke soak stays under budget.
  • compaction state-equivalence - exact reconstruction across the 30-fold boundary; a store test asserts the base rewrite + folded-row delete land in one tx.
  • 500-stroke soak stays under budget, folded ≤ 30 (boot-replay cap), reconstructs exactly.
  • Live tiled-boot.mjs gains an eviction phase (folded rows round-trip through IDB, boot == live paint): 10/10 on real GPU Chrome.

Checks

npm run lint clean, npx tsc --noEmit clean, npx vitest run 825/825, npm run build:app OK. Live: tiled-boot.mjs 10/10, tiled-restore.mjs 8/8 (no regression).

barakbl added 2 commits July 17, 2026 01:24
Bounds the on-mode delta chain's growth (memory, disk, and boot replay), replacing
PR10's eager fold-into-base with the deferred foldedIds model from the plan.

- Eviction is meta-only: TileShadow moves the oldest active entries into a `folded`
  list (no pixel work) while the window is over MAX_UNDO count OR the byte budget
  (min(32MB, storage.estimate().quota / 20), sized at boot). It keeps at least one
  active entry, so a user at the stack bottom overshoots transiently, never losing
  the entry they just made. After a commit the pointer sits at the tip, so eviction
  only ever folds entries strictly below it.

- Compaction: once `folded` passes 30, one enqueued step bakes every folded entry
  into the base (the deferred cost) and bumps the base version. The store rewrites
  the base and deletes the folded rows in the same tx, so it never holds folded
  rows without a base to anchor them.

- Reconstruction / serialize / hydrate apply base + folded + active, so boot
  replays the folded rows and stays exact across a compaction boundary.

- Store: meta2 gains `foldedIds`; folded + active share one `entry:<id>` row
  namespace tracked by `savedRowIds`. A pre-PR11 meta2 (no foldedIds) still loads,
  with an empty folded list.

Tests: fold/pointer-remap, byte-budget eviction, compaction state-equivalence,
undo/redo-after-eviction, foldedIds store round-trip, compaction-tx (base rewrite +
folded-row delete), and a 500-stroke soak that stays under budget + the folded cap
while reconstructing exactly. Live tiled-boot.mjs gains an eviction phase (folded
rows round-trip through IDB): 10/10 on real GPU Chrome. Quota-error recovery + the
one-time toast are PR11 part 2.
@barakbl
barakbl merged commit 49ece00 into main Jul 16, 2026
4 checks passed
@barakbl
barakbl deleted the feat/undo-tiled-eviction branch July 16, 2026 22:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant