# Browser telemetry

## Indice

1. Scelta della superficie browser
2. Trace e long task
3. DOM, rendering e layout
4. Listener, observer e memoria
5. Network e asset
6. Diagnostica opt-in
7. Errori di misura

## 1. Scelta della superficie browser

Rispetta la superficie richiesta dall'utente. Se Chrome è già autenticato, riusa quella sessione e la tab esistente. Non aprire un browser parallelo che perda token, storage o stato cross-tab. Se il controllo browser fallisce, raccogli prima la diagnostica del collegamento e concorda il fallback.

Non leggere cookie, password o storage sensibile. Non scrivere token negli artifact.

## 2. Trace e long task

Per una trace Chrome:

1. identifica l'intervallo esatto del sintomo;
2. separa main thread, worker e network;
3. usa Bottom-Up per costo aggregato e Call Tree per sequenza;
4. annota long task, scripting, style/layout, paint e GC;
5. collega le funzioni a initiator, file e callback owner;
6. confronta con un secondo campione prima di generalizzare.

Calcola TBT come somma di `max(0, durata task - 50 ms)` nell'intervallo dichiarato. Non usare l'intera registrazione se contiene attività estranea.

Quando la trace è JSON grande, estrai indici e aggregati con uno script read-only invece di caricarla integralmente nel contesto. Conserva timestamp, category, duration, name e stack/args strettamente utili.

## 3. DOM, rendering e layout

Raccogli snapshot compatti:

```js
const snapshot = {
  nodes: document.querySelectorAll('*').length,
  busy: document.querySelectorAll('[aria-busy="true"]').length,
  grids: [...document.querySelectorAll('[role="grid"], [role="treegrid"]')].map((el) => {
    const rect = el.getBoundingClientRect();
    return { width: rect.width, height: rect.height, visible: rect.width > 0 && rect.height > 0 };
  })
};
```

Non scansionare tutte le celle a ogni mutation o scroll. Per readiness strutturale misura header e una riga rappresentativa, quindi invalida solo su cambi realmente strutturali.

Per trovare layout thrashing:

- conta geometry reads (`getBoundingClientRect`, `offset*`, `scroll*`);
- conta style/class writes;
- verifica se letture e scritture si alternano nello stesso frame;
- verifica mutation generate dallo stesso controller che le osserva;
- registra durata e motivo di ogni pass strutturale.

## 4. Listener, observer e memoria

Per ogni owner verifica:

- identità stabile della callback usata in add/remove;
- scope: pagina, componente, interazione o frame;
- cleanup su release, error, navigation e disposal;
- `MutationObserver.disconnect()` e `ResizeObserver.disconnect()`;
- `cancelAnimationFrame` e `clearTimeout`/`clearInterval`;
- rilascio di `DotNetObjectReference` o equivalenti;
- callback obsolete ignorate tramite generation/lifetime token.

Preferisci contatori applicativi opt-in per owner (`map`, `calendar`, `drag`, `grid`) a un solo totale globale. Un totale stabile può nascondere un leak compensato da cleanup altrove.

Per un soak:

1. acquisisci baseline a pagina stabile;
2. esegui N cicli identici;
3. forza GC solo se l'ambiente lo consente;
4. attendi quiete di timer/rete;
5. confronta mediane o plateau, non un singolo punto.

## 5. Network e asset

Per richieste duplicate registra:

- URL normalizzato e metodo;
- initiator/call site;
- start/end e sovrapposizione;
- status e byte trasferiti;
- memory/disk cache;
- chiave logica e lingua/tenant se influenzano il risultato.

Non modificare protocolli privati di una libreria se la richiesta duplicata è servita da cache e non produce long task o byte materiali.

Verifica gli artifact di publish separatamente dal dev server. Placeholder di asset visibili in Debug non provano da soli un errore del publish.

## 6. Diagnostica opt-in

Esporre diagnostica soltanto dietro flag esplicito, query parameter o ambiente non-production. Un hook utile offre:

- `reset()`;
- `snapshot()` serializzabile;
- generation e reason;
- pass/duration;
- DOM reads/writes;
- readiness/fallback;
- controller/listener/observer/timer attivi.

Non includere payload applicativi, token, header o response body. Mantieni overhead quasi nullo quando disabilitato.

## 7. Errori di misura

Evita questi errori:

- confrontare build Debug e Release come se fossero equivalenti;
- misurare il tempo del comando di automazione come latenza UI;
- aggiungere `sleep` al valore misurato;
- lasciare DevTools recording, screenshot continui o logging massivo durante il benchmark senza dichiararlo;
- confondere download/cache con main-thread stall;
- dichiarare leak da una sola crescita heap;
- dichiarare fix da un solo reload riuscito.
