Skip to content

fix(perf): audit and vitals agree on LCP via shared apply_lcp_fields (iter-125) - #165

Merged
ractive merged 3 commits into
mainfrom
iter-125/perf-audit-lcp-unavailable
Jul 19, 2026
Merged

fix(perf): audit and vitals agree on LCP via shared apply_lcp_fields (iter-125)#165
ractive merged 3 commits into
mainfrom
iter-125/perf-audit-lcp-unavailable

Conversation

@ractive

@ractive ractive commented Jul 19, 2026

Copy link
Copy Markdown
Owner

Summary

  • perf audit fabricated a false all-clear on pages where LCP is unmeasurable: it rebuilt its .results.vitals LCP triple with a bare lcp.map(|v| rate(v, 2500, 4000)) that lacked the iter-83 N7 unavailable-guard. When the DOM approximation fabricates a startTime: 0 entry (compute_lcp == Some(0.0), is_lcp_approximate == true), audit reported lcp_ms: 0.0, lcp_rating: "good" — while perf vitals on the same page correctly reported lcp_ms: null, lcp_rating: "unavailable" (dogfooding-session-61).
  • Extracted the guard + lcp_note/lcp_approximate annotation into a single pub(crate) apply_lcp_fields helper in perf.rs; both run_vitals and run_audit now route the LCP triple through it, so the two commands share one code path and cannot drift again.
  • render_audit_text now prints [unavailable] (no 0.00ms good) since lcp_ms is null for the unmeasurable case; measurable-LCP pages (~587 ms regression-agent case) are unaffected — the helper reduces to the same rate(v, 2500, 4000) path.
  • The other vitals fields (fcp, ttfb, cls, tbt) were already in agreement; only the LCP triple was in scope.

Test plan

  • unit_perf_audit_lcp_unavailable_when_missing — audit block with lcp = None yields "unavailable" / null (not "good"/0.0).
  • unit_perf_audit_lcp_unavailable_when_approximate_zero — the comparis.ch-class case: Some(0.0) + approximate → "unavailable" / null.
  • unit_perf_audit_lcp_unavailable_matches_vitals — audit block equals vitals block field-for-field for both missing-LCP and approximate-zero inputs via the shared helper.
  • unit_perf_audit_lcp_rated_when_approximate_nonzero / unit_perf_audit_lcp_rated_when_measurable — negative controls: real/measurable LCP is still rated, not nulled.
  • live_perf_audit_lcp_unavailable — text-only fixture page, no LCP candidate: perf audit reports .results.vitals.lcp_rating == "unavailable", .lcp_ms == null (verified against real Firefox).
  • live_perf_audit_vitals_lcp_parity — same page, same session: perf audit .results.vitals.{lcp_ms, lcp_rating} equals perf vitals .results.{lcp_ms, lcp_rating} (verified against real Firefox).
  • cargo fmt / cargo clippy --workspace --all-targets -- -D warnings / cargo test --workspace -q all clean.
  • check-iteration-ready 10/10 PASS (with FF_RDP_LIVE_TESTS=1).

🤖 Generated with Claude Code## Claims vs code
<generated 2026-07-19T15:29:43Z by ralph-loop>

No claims extracted from commit messages.

ractive and others added 3 commits July 19, 2026 17:27
…er-125)

`perf audit` rebuilt its .results.vitals LCP triple with a bare
`lcp.map(|v| rate(v, 2500, 4000))` that lacked the iter-83 N7
unavailable-guard, so on a page with no measurable LCP — where the DOM
approximation fabricates a `startTime: 0` entry (compute_lcp == Some(0.0),
is_lcp_approximate == true) — audit reported `lcp_ms: 0.0,
lcp_rating: "good"`: a false all-clear, while `perf vitals` on the same
page correctly reported `lcp_ms: null, lcp_rating: "unavailable"`.

Extract the guard + note/approximate annotation into a single
`pub(crate) apply_lcp_fields` helper and call it from both `run_vitals`
and `run_audit`, so the two commands share one LCP code path and cannot
drift. render_audit_text renders `[unavailable]` (no `0 ms good`) since
lcp_ms is now null.

Adds 5 audit-side unit tests (twins of the vitals tests, incl.
unit_perf_audit_lcp_unavailable_matches_vitals) and a new live test file
live_perf_audit_lcp_unavailable.rs with live_perf_audit_lcp_unavailable
and live_perf_audit_vitals_lcp_parity — both verified against real
Firefox.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The `unit_perf_audit_lcp_unavailable_matches_vitals` AC slug starts with
`unit_`, which ac-fidelity-check heuristic 1 (live_/test_/bench_) does not
match; backtick-quote it (and `apply_lcp_fields`) so heuristic 2 resolves
it against the perf.rs diff.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
iter-125 fixed an analogous vitals/audit drift by extracting the divergent
logic into a shared helper plus an explicit parity assertion between the two
call sites. Point iter-126 at the same pattern for the network JSON shape
fix (shared builder + parity test between navigate and the standalone
network command), and flag that firefox_refs line numbers should be
re-verified against main before starting.
@ractive
ractive merged commit de2402d into main Jul 19, 2026
10 checks passed
@ractive
ractive deleted the iter-125/perf-audit-lcp-unavailable branch July 19, 2026 15:38
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