fix(shim): live viewport size and a ResizeObserver that fires - #49
Merged
Merged
Conversation
added 5 commits
September 25, 2026 08:43
The engine owns innerWidth and innerHeight as live accessors over the document viewport, but a page's scripts run before the host sets that viewport, so at boot they read 0. The shim took the 0 for a missing value and replaced the accessors with a fixed 1440x960 for good. A 1344-wide headless page reported 1440 for its whole life, and anything clamped to the viewport was placed against a width the page does not have. The shim now captures the engine's getters and answers with them, falling back to 1440x960 only while they still read 0. screen and the dimension branch of matchMedia read the same live size. Assigning innerWidth keeps the assigned value, as a browser's replaceable attribute does. Measured in chuzz-headless on a 1344x900 page: innerWidth read 1440x960 after the viewport was set; it now reads 1344x900.
The stub never fired, on the grounds that nothing could measure a box from script so any entry would carry a zero size. getBoundingClientRect now returns laid-out boxes, and the silence had become the bug: a component that measures, moves and relies on the observer to settle was left where its first frame put it. @pathscale/ui's Select opened its list at the left edge of the window and kept it there. The observer measures border boxes on animation frames. The engine has no resize notification, so measuring is armed by observe(), resize and scroll, pointer, keyboard and input events, and by a size change it finds, and disarms after 30 frames with no change, so a page that observes something permanently still goes idle. Entries follow the specification's shape; contentRect and the box sizes describe the border box because computed style does not report padding to script. The first observation reports any size other than 0x0, and a throwing callback is reported without stopping the others. Measured in chuzz-headless: an observed table reported nothing before; it now reports 0 to 968 on observe and 968 to 600 when resized. The stock Select list moved from left 88, under a trigger at 512, to left 479, under its trigger at 479.
The observer measured border boxes only, because computed style reported no padding or border to script. ps-blitz now reports them (pathscale/ps-blitz#102), so the content box is the border box less both, which is what an observer watches by default; { box: 'border-box' } is honoured. On an engine without the edges they read as zero and the content box falls back to the border box, which is the previous behaviour. Measured on a box with content 100x20, padding 10 and border 2: the published engine reports 124x44 (the fallback); ps-blitz#102 reports a content box of 100x20 at x 12 and a border box of 124x44.
Ships the live viewport size and a ResizeObserver that fires, so consumers of the headless host (every fleet site's QA) get them.
/private/tmp exists only on macOS, and naming it pinned the script to one kind of machine. The default artifact directory now goes under TMPDIR, falling back to /tmp, which is where the rest of the script already looks.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two web-API shim bugs in
apps/chuzz/src/document_loader.rs, found while debugging an@pathscale/uiSelect on crates.vip. The dropdown opened at the left edge of the window and stayed there. Both stubs were written when nothing could measure a box from script;getBoundingClientRectnow returns laid-out boxes, so both can be real.1.
innerWidth/innerHeightreported a fixed 1440x960 foreverThe engine (ps-blitz-script 0.4.11) owns them as live accessors over the viewport. A page's scripts run before the host sets that viewport, so at boot they read 0. The shim took 0 for "missing" and replaced the accessors with 1440x960 for good.
Fix: capture the engine's getters and answer with them, falling back to 1440x960 only while they still read 0.
screenandmatchMedia's dimension branch read the same live size. AssigninginnerWidthkeeps the assigned value (replaceable attribute). No getter reads a shimmed name, so the old recursion cannot return.2.
ResizeObservernever firedA silent stub. A component that measures, moves and relies on the observer to settle was left wherever its first frame put it.
Fix: a real observer over border boxes, measured on animation frames. With no engine resize notification, measuring is armed by
observe(), resize/scroll, pointer, keyboard and input events, and by a size change it finds; it disarms after 30 quiet frames, so a page that observes something permanently still goes idle for rendered QA's idle and drift checks. Entries follow the specification's shape;contentRectand the box sizes describe the border box because computed style does not report padding to script.Measured (chuzz-headless, 1344x900, a Select in a table row, stock
@pathscale/ui3.2.4)innerWidth x innerHeightafter the viewport is setResizeObserveron a table, then resizedThe remaining one-frame misplacement is
@pathscale/ui's own, fixed in pathscale/ui#296.Checks
cargo build --release -p chuzz --bin chuzz-headless --no-default-features --features capture,javascript: no warnings.cargo test --release -p chuzz --no-default-features --features capture,javascript: 81 pass, 3 fail. The 3 arecapture::teststhat needsystem-fonts(a blank capture without a font); they fail identically on master with the same features.cargo fmt -p chuzz -- --check: clean.system-fonts, the GUI.3.
ResizeObserverreports the content boxFollow-up now that ps-blitz reports padding and border (pathscale/ps-blitz#102): the content box is the border box less both, which is what an observer watches by default;
{ box: 'border-box' }is honoured. On an engine without the edges they read as zero and the content box falls back to the border box (the previous behaviour), so this is safe on the published engine.Measured on a box with content 100x20, padding 10, border 2: published engine 124x44 (fallback); ps-blitz#102 content 100x20 at x 12, border box 124x44.
Fixed in the engine instead (pathscale/ps-blitz#102)
MutationObserver: the shim's stub never fired. ps-blitz now defines a real one; the shim'stypeof ... === 'undefined'guard then leaves it alone. chuzz picks it up with the next ps-blitz release (caret^0.4).getComputedStylepadding, border and margin, andclientWidthas the padding box.Release
Bumps chuzz to 0.1.40, so merging publishes a new
headless-v0.1.40host. Fleet sites whose QA pins the headless-host action need their pin moved to pick it up.Against the published engine
ps-blitz 0.4.12 is on crates.io and this branch resolves it through
^0.4with no manifest change. A release build from crates.io (no local override) on the probe page:MutationObserverreports attribute and child changes,ResizeObserverreports a 100x20 content box (border box 124x44),innerWidthis 1344, and the Select opens under its trigger.Hard-coded local path
scripts/qa-visible-app.shmade its default artifact directory under/private/tmp, which exists only on macOS; it now uses${TMPDIR:-/tmp}, where the rest of the script already looks.bash -npasses and the default resolves underTMPDIR.