Skip to content

Raise retained widget layout budget 1024 -> 2048 nodes per view - #409

Open
slicenferqin wants to merge 1 commit into
vercel-labs:mainfrom
slicenferqin:fix/raise-layout-budget-4096
Open

Raise retained widget layout budget 1024 -> 2048 nodes per view#409
slicenferqin wants to merge 1 commit into
vercel-labs:mainfrom
slicenferqin:fix/raise-layout-budget-4096

Conversation

@slicenferqin

Copy link
Copy Markdown

Fixes #408.

What

Doubles the retained per-view widget budgets:

  • canvas_limits.max_canvas_widget_nodes_per_view 1024 → 2048
  • canvas_limits.max_canvas_widget_semantics_per_view 1024 → 2048
  • automation.snapshot.max_widgets_per_view in lockstep (the existing lockstep test in canvas_widget_layout_tests.zig enforces the mirror)

Why

The 1024 cap was sized against "the measured worst realistic three-pane view is ~500 nodes". Real list-dense views blow past that: our production app (session rail enumerating ~50 rows, streaming detail timeline, model-picker dialog listing ~60 models with provider-group headers) measures 1036/1024 nodes on its dialog frame — 12 nodes over.

The failure mode is much worse than "fail loudly": adoptWidgetLayoutWidgetLayoutListFull discards the whole rebuild, so the interaction that pushed the view over budget (opening a dialog) appears to do nothing — controls look dead — and any view that sits over budget drops every subsequent frame, wedging its interactions entirely.

2048 covers the measured view with ~2x headroom. These are validation bounds over fixed-capacity address space (pages touched only as used), so the raise costs address space, not committed memory.

Why not 4096

Tried it first. The session record/replay tests (session_tests, media_surface_tests, effects_video_tests, …) inline record+replay harnesses and UiApp constructions into a single test function; on macOS those frames already run ~11 MiB of stack at 1024, and 4096 pushes them to ~17 MiB — past the main-thread stack limit: 53 tests crash with SIGSEGV at frame entry. At 2048 zig build test is green.

Longer term, apps retaining unbounded collections will outgrow any fixed cap; windowed retention for list widgets would remove the cliff. (Happy to open a separate issue for that.)

Test

zig build test (zig 0.16.0, macOS arm64): 3366/3381 pass, 14 skipped, 1 failed — the one failure (ui_app_tests.test.a failed build keeps the still-matching pair live) reproduces identically on unmodified main when the shard runs in isolation (markup-build cache-state flake), so it is not caused by this change.

A production three-pane app (session rail ~50 rows, streaming detail
timeline, model-picker dialog listing ~60 rows) measures 1036 retained
widget nodes on its dialog frame — 12 over the 1024 cap. The
WidgetLayoutListFull adoption failure discards the whole frame, so
opening the dialog leaves every control visibly dead, and a view that
sits over budget wedges interactions on every invalidated frame.

Doubling the budget covers the measured view with ~2x headroom. The
automation snapshot cap moves in lockstep (the existing lockstep test
enforces it). 4096 was ruled out: session record/replay tests inline
record+replay harnesses into one test frame (~11 MiB at 1024 on macOS),
and 4096 pushes those frames past the main-thread stack limit (53
crashes); 2048 keeps zig build test green.

Fixes vercel-labs#408
@vercel

vercel Bot commented Aug 27, 2026

Copy link
Copy Markdown

@slicenferqin is attempting to deploy a commit to the Vercel Labs Team on Vercel.

A member of the Team first needs to authorize it.

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.

Per-view widget layout budget (1024 nodes) drops whole frames on real multi-pane app views

1 participant