Skip to content

Add native performance attribution - #164

Open
mattcosta7 wants to merge 1 commit into
v1.3/03-frame-fidelityfrom
v1.3/04-native-attribution
Open

Add native performance attribution#164
mattcosta7 wants to merge 1 commit into
v1.3/03-frame-fidelityfrom
v1.3/04-native-attribution

Conversation

@mattcosta7

Copy link
Copy Markdown
Member

Summary

  • retain bounded native attribution for layout-shift sources, Long Animation Frame forced style/layout work, Element Timing entries, and script Resource Timing entries
  • preserve total counts separately from bounded evidence and cap selectors, URLs, labels, sources, and retained records
  • expose structured attribution through the public metric contract and existing panel sections
  • document the new evidence and add a minor changeset

Stack

Depends on #163 (v1.3/03-frame-fidelity).

Validation

  • 894 tests across Chromium, Firefox, and WebKit
  • focused attribution, contract, manager, and panel tests
  • npm run tsc
  • npm run lint (one pre-existing warning only)
  • npm run build
  • attw
  • publint

@mattcosta7
mattcosta7 marked this pull request as ready for review August 3, 2026 16:34
@mattcosta7
mattcosta7 requested a review from a team as a code owner August 3, 2026 16:34
Copilot AI review requested due to automatic review settings August 3, 2026 16:34
@mattcosta7 mattcosta7 self-assigned this Aug 3, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds bounded native performance attribution to collectors, public metrics, and panel displays.

Changes:

  • Captures layout-shift, LoAF, Element Timing, and script-resource attribution.
  • Exposes bounded evidence separately from total counts.
  • Adds documentation, tests, and a minor changeset.
Show a summary per file
File Description
.changeset/add-native-attribution.md Records the minor release.
README.md Documents attribution metrics.
performance-panel.tsx Displays attribution evidence.
index.ts Exports attribution types.
index-universal.ts Exports attribution types universally.
core/performance-types.ts Defines public attribution contracts.
collectors/attribution.ts Adds bounding and selector helpers.
collectors/paint-collector.ts Collects script-resource attribution.
collectors/long-animation-frame-collector.ts Collects forced layout attribution.
collectors/layout-shift-collector.ts Collects layout-shift sources.
collectors/element-timing-collector.ts Collects bounded element evidence.
collectors/collector-manager.ts Maps attribution into public metrics.
collectors/__tests__/attribution.browser.test.ts Tests attribution bounds.
collectors/__tests__/paint-collector.browser.test.ts Tests resource attribution.
collectors/__tests__/long-animation-frame-collector.browser.test.ts Tests LoAF attribution.
collectors/__tests__/layout-shift-collector.browser.test.ts Tests shift sources.
collectors/__tests__/element-timing-collector.browser.test.ts Tests bounded element records.
collectors/__tests__/collector-manager.browser.test.ts Tests manager contract fields.
__tests__/performance-panel.browser.test.tsx Tests panel visibility.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 19/19 changed files
  • Comments generated: 4
  • Review effort level: Balanced

Comment on lines +12 to +29
export function getElementSelector(node: Node | null): string {
const element = node instanceof Element ? node : node?.parentElement
if (!element) return 'unknown'

if (element.id) {
return limitAttributionString(`#${element.id}`, 'unknown', ATTRIBUTION_SELECTOR_MAX_LENGTH)
}

const timing = element.getAttribute('elementtiming')
if (timing) {
return limitAttributionString(`[elementtiming="${timing}"]`, 'unknown', ATTRIBUTION_SELECTOR_MAX_LENGTH)
}

const className = typeof element.className === 'string' ? element.className : ''
const classes = className.split(/\s+/).filter(Boolean).slice(0, 2).join('.')
const selector = `${element.tagName.toLowerCase()}${classes ? `.${classes}` : ''}`
return limitAttributionString(selector, 'unknown', ATTRIBUTION_SELECTOR_MAX_LENGTH)
}
Comment on lines +393 to +395
rawRenderTime: Math.round(e.rawRenderTime * 10) / 10,
loadTime: Math.round(e.loadTime * 10) / 10,
rawLoadTime: Math.round(e.rawLoadTime * 10) / 10,
Comment on lines +156 to +157
this.#elementCount++
addBoundedAttribution(this.#elements, record)
Comment on lines 94 to +98
if (resourceEntry.initiatorType === 'script') {
const scriptTime = resourceEntry.responseEnd - resourceEntry.fetchStart
if (scriptTime > 0) {
this.#scriptEvalTime += scriptTime
this.#scriptResourceCount++
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.

2 participants