Skip to content

perf(domformat): preserve sparse prepared-state publication - #88

Open
alowpoly wants to merge 6 commits into
mainfrom
domformat-sparse-publication
Open

perf(domformat): preserve sparse prepared-state publication#88
alowpoly wants to merge 6 commits into
mainfrom
domformat-sparse-publication

Conversation

@alowpoly

@alowpoly alowpoly commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Outcome

The ordinary adjacent paged hot path is genuinely proportional to declared changes. Sparse playback and variant stages borrow validated resident-page ranges, mutate only those targets in canonical state, and publish only those targets. Adjacent surface/profile publication reuses typed scratch storage. Complete reconstruction remains only at semantic barriers and failure recovery where an absolute row is required.

No public API, codec, transport, renderer, producer, adapter integration, or Worker surface is added. Flowerbox is intentionally excluded. Synthetic dimensions are informed only by the pinned published Cloth, Solitaire, and Gravity Well sources.

Runtime changes

  • keep sequential paged playback/variant stages range-backed and pin borrowed resident pages through commit
  • mutate canonical shape transforms, shape visibility, and leaf transforms in place for adjacent rows
  • publish sequential variants directly from changed target ranges
  • reuse typed dirty buffers for adjacent surface, visibility, and profile publication
  • preserve immutable complete-stage snapshots for seek, reconstruction, rollback, and page-start barriers
  • preflight prospective residency/live-row bytes before eviction, fetch, materialization, canonical mutation, or DOM publication
  • preserve class → transform → atlas address → visibility ordering, hidden-leaf dirt, reveal catch-up, interaction-forced visibility, and stable DOM identity

Adversarial follow-up

Two independent adversarial passes were applied after the sparse implementation. The final follow-up at 16dd34b3 closes the reproduced transactional/recovery gaps:

  • paged seek and inline-playback/paged-variant seek commit before mutating engine-local playback state
  • viewport-profile visibility stages exactly once, after a successful commit
  • failed paged bank selection restores the prior bank/timeline/frame/tick; a post-commit surface failure coherently retains the new bank and remains recoverable
  • failed surface publication can recover directly to the same frame, a held timeline frame, a later frame, an arbitrary seek, or a declared/fallback jump without re-toggling visibility
  • deferred shape/profile visibility is preserved across a surface exception
  • an intermediate advanceMany commit failure publishes its successfully committed prefix coherently before rethrowing, so retry cannot strand stale DOM
  • rejected residency/live-row admissions no longer ratchet diagnostic peaks before state admission
  • the maximum valid uint16 leaf target (65,535) no longer collides with the forced-surface exhaustion sentinel
  • range stages retain their resident-page pins through commit, and retained complete stages remain immutable snapshots

Trace evidence is now fail-closed: Chromium uses recordAsMuchAsPossible, records a bounded three-category set, requires dataLossOccurred === false, preserves raw events before interpretation, and requires positive RunTask containing FireIdleCallback attribution before applying the unchanged 50 ms page-preparation limit. General RunTask/cadence observations are intentionally not hard gates.

Visit and allocation evidence

  • one change among 1,984 paged variant targets: 1 logical visit and 1 comparison, not 1,984
  • Cloth-shaped adjacent row: 217 canonical + 217 publication visits for 200 dense and 17 sparse transforms
  • Solitaire-shaped adjacent row: 32 canonical + 32 publication visits, not a 1,952-target row clone
  • Gravity-Well-shaped mid-page row: 40 canonical + 40 publication visits and 40 variant comparisons, not a 1,984-target scan
  • focused adjacent surface row: 1 lighting + 1 visibility visit, zero full reconstruction
  • final diagnostic windows: zero playback/surface full-row reconstructions in all three workloads; Gravity Well has four variant reconstructions, exactly its four page-start keyframe barriers

The bounded TypeScript source audit reports 30 forbidden source-form sites at b3b30bbb → 0. The candidate guard is broader now: 14 named scopes, including the adjacent helper call boundaries, with fail-closed helper-renaming and mutation tests. It rejects typed/ordinary slices, Array.from, array/typed-array constructors, array literals/spreads, Set/Map, sorting, and nested closures in those named scopes.

This is a bounded source-form tripwire, not general JavaScript heap instrumentation. Sparse staging still creates bounded stage objects; the claim is no guarded target-sized collection/source forms in the named sequential paths.

Remaining full scans are intentional:

  • initial publication and arbitrary/nonsequential seek reconstruction
  • playback/variant page-start keyframes and boundary validation
  • same-frame and catch-up synchronization barriers against potentially stale DOM
  • transactional failure recovery
  • explicit complete-stage rollback/retry paths

Chromium trace evidence

The original performance comparison alternated five independent 42-second runs per revision (b3b30bbb baseline versus 315447b9 candidate). Those runs support reduced JavaScript publication work, not a blanket cadence speedup:

Metric (mean, n=5) Baseline Sparse candidate Delta
maximum main-thread task 22.180 ms 23.503 ms +5.96%
median per-run maximum task 21.464 ms 21.421 ms -0.20%
maximum RAF/presentation gap 125.120 ms 120.100 ms -4.01%
cadence p50 16.580 ms 16.600 ms +0.12%
cadence p95 50.000 ms 50.140 ms +0.28%
page-preparation maximum 5.770 ms 5.340 ms -7.45%
page-preparation p95 0.438 ms 0.423 ms -3.42%

Mean inclusive attribution changed as follows:

  • FunctionCall: 500.843 ms → 407.385 ms (-18.66%)
  • FireAnimationFrame: 657.425 ms → 550.376 ms (-16.28%)
  • Layerize: 7,199.469 ms → 7,189.294 ms (-0.14%)
  • Commit: 2,442.976 ms → 2,436.316 ms (-0.27%)
  • Paint: 1,471.029 ms → 1,469.486 ms (-0.10%)

The final recovery/evidence follow-up was then traced twice from the identical 101,464-byte tarball (93b3dba91608c9a7cd4aeb8928f15f544bda6df34335f387a9b0f9ec6de19f75): once during release and once from clean commit 16dd34b3.

Final-package trace Release run Clean exact-commit run
duration 42.013 s 42.015 s
raw events 4,439,639 4,464,124
data loss false false
maximum main-thread task 18.804 ms 31.924 ms
maximum RAF/presentation gap 124.9 ms 133.4 ms
cadence p50 16.6 ms 16.6 ms
cadence p95 58.3 ms 50.5 ms
page-preparation maximum 5.302 ms 4.593 ms
attributed preparation tasks 4,275 4,202

The clean run crossed 6/12/11 timing-window page boundaries for Cloth/Solitaire/Gravity Well and at least 2/4/4 boundaries in the separate instrumented visit windows. Stable DOM identity held throughout. Remaining gaps were dominated by Layerize, Commit, and Paint, not sparse publication or page validation.

The clean run verified the exact published cssGraphics source manifest at 083532aa66599f1ff4618b987ccc5df462631996 (Cloth client/shadow patch, Gravity Well prepared playback, and Solitaire prepared playback). No adapter code is executed by the synthetic trace and no adapter behavior/performance parity is claimed.

Correctness and visual parity

  • exact adjacent, boundary, wrap/final-to-first, arbitrary seek, combined playback/variant atomicity, failed-seek/bank/surface/catch-up recovery, held-frame recovery, and maximum-leaf tests pass
  • production, alternate, and independent N-version browser paths match with stable DOM identity and exact fixture pixels
  • release browser evidence reports maximum channel delta 0 for both alternate and N-version viewers
  • the complete-gallery Chromium differential previously passed all 304 models, 199,847 retained leaves, 736 animated frames, 1,040 states, and 425,984,000 pixel comparisons with zero failures
  • the final gallery gate revalidated all 304 documents; the corpus remains broad retained-DOM/lifecycle evidence but contains no paged, variant, or surface workload, so core sparse claims come from dedicated fixtures

Verification

  • pnpm --filter @layoutit/polycss-domformat test:coverage316/316; 96.69% lines, 92.02% branches, 94.65% functions
  • pnpm --filter @layoutit/polycss-domformat test:page-preparation — pass
  • pnpm --filter @layoutit/polycss-domformat test:release — pass
  • pnpm gallery:domformat:verify — 304 models / 199,847 leaves
  • pnpm test — pass
  • pnpm build — pass
  • pnpm check:readmes — pass
  • pnpm test:scripts — 22/22
  • git diff --check — pass

Deterministic packed package: 101,464 bytes, below the unchanged 100 KiB ceiling; unpacked size 375,793 bytes. The package is deterministic, runtime-only, install-smoke-tested, CLI/type-declaration tested, and accepts the independent producer.

Worker follow-up

A separate Worker-preparation PR is not currently justified. Attributed preparation tasks remained below 17 ms in the full release matrix and 5.302 ms in the final publication traces, leaving substantial headroom under the unchanged 50 ms gate. A Worker proposal should wait for a fresh trace showing validation itself as a material main-thread bottleneck.

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