Skip to content

fix(core): report the tile offset a clamped upload replaced, and which snapshot it came from - #2373

Open
aryanku-dev wants to merge 1 commit into
masterfrom
fix/PER-10200-report-clamped-tile-offsets
Open

fix(core): report the tile offset a clamped upload replaced, and which snapshot it came from#2373
aryanku-dev wants to merge 1 commit into
masterfrom
fix/PER-10200-report-clamped-tile-offsets

Conversation

@aryanku-dev

@aryanku-dev aryanku-dev commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Fixes the diagnosability half of PER-10200.

Problem

On App Automate iOS full-page capture, the device-side percyScreenshot executor can return a negative header_height for a tile. header_height is the number of pixels cropped off the top of a tile before stitching — it removes the fixed device chrome and the band the previous tile already showed.

PercyConfig.validate repairs out-of-range values instead of rejecting them (packages/config/src/validate.js, keyword === 'minimum'Math.max(data, schema)), and percy.upload() only warns and continues. So the negative silently became 0, the snapshot uploaded, and percy-api cropped nothing off the tile top — stitching the iOS status bar and the app nav bar into the middle of the full-page screenshot. The customer gets a plausible-looking but wrong baseline rather than a visible failure.

The only signal was:

[percy] Invalid upload options:
[percy] - tiles[1].headerHeight: must be >= 0

Two things missing there:

  • No snapshot name. options.meta was assigned after the validation block, so these lines carried no meta. A run that warns about three different pages produces three identical anonymous pairs, with no way to tell which tiles[n] belongs to which page.
  • No value. The number that was actually received never reached the logs, and neither did the fact that it had been substituted.

Diagnosing one such build needed the stored tiles rows out of the DB plus a hand-rebuilt stitch from the raw GCS tiles. That should have been readable from the CLI output.

Change

  • packages/config/src/validate.js — record received / clampedTo on clamp errors. Additive; the other two validate() consumers (percy.js:224, snapshot.js:255) read only path/message and are unaffected.
  • packages/core/src/percy.js — set the logging meta before validating so warnings are attributed to their snapshot, and report the substitution.
[percy] - tiles[1].headerHeight: must be >= 0 (received -318, continuing with 0)

The clamp behaviour itself is deliberately unchanged — this only makes it visible. The bad value originates device-side in the App Automate capture routine and is fixed there; rejecting the upload here would turn a wrong screenshot into a failed build for customers whose only recourse is an upstream fix.

Testing

  • packages/core/test/percy.test.js — two new specs: the clamp is reported with the received value (using the real PER-10200 tile geometry), and validation warnings carry their snapshot's meta.
  • packages/config/test/index.test.js — existing clamp assertions updated for the new fields.
  • @percy/config: 82/82 pass. @percy/core percy.test.js: 137/137 pass. yarn lint clean.

🤖 Generated with Claude Code

…h snapshot it came from

An App Automate iOS fullpage capture can return a negative `header_height`
for a tile. `PercyConfig.validate` repairs out-of-range values rather than
rejecting them, so the negative became 0 and the snapshot uploaded anyway —
with no top crop, which stitches the device status bar and app nav bar into
the middle of the full-page image. The only signal was:

    [percy] Invalid upload options:
    [percy] - tiles[1].headerHeight: must be >= 0

which names neither the snapshot nor the value that was thrown away, so a run
warning about several pages gives no way to tell them apart. Diagnosing one
such build (PER-10200) needed the stored tile rows and a hand-rebuilt stitch.

Record `received`/`clampedTo` on clamp errors, set the logging meta before
validating so the warnings are attributed to their snapshot, and report the
substitution:

    [percy] - tiles[1].headerHeight: must be >= 0 (received -318, continuing with 0)

The clamp itself is unchanged — this only makes it visible. The bad value
originates device-side and is fixed there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@aryanku-dev
aryanku-dev requested a review from a team as a code owner August 7, 2026 05:40
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