fix(studio): stop composition fetch-404 flood and cap error telemetry

Two fixes for the 3M+ unhandled_promise_rejection events/day spike:

1. Filter: suppress "Error fetching ... 404" rejections from composition
   code — these are asset-not-found content errors, not Studio bugs.

2. Rate-limit: cap both error and rejection telemetry at 50 per session.
   After the cap, emit a single *_cap_reached event so we know capping
   occurred without generating unlimited events.

3. Root cause: webAudioTransport now checks response.ok before decode
   and caches failed URLs in _failedSrcs so repeat ticks don't re-fetch
   the same 404 on every playback frame.

Also add playground/ to fallow ignorePatterns — local experiment
directory was tripping the audit gate.
This commit is contained in:
Miguel Ángel
2026-05-22 13:22:00 -04:00
parent aebb7b2660
commit 36de02c4bf
3 changed files with 41 additions and 1 deletions
@@ -18,6 +18,7 @@ export type ScheduledSource = {
export class WebAudioTransport {
private _ctx: AudioContext | null = null;
private _bufferCache = new Map<string, AudioBuffer>();
private _failedSrcs = new Set<string>();
private _activeSources: ScheduledSource[] = [];
private _masterGain: GainNode | null = null;
// Composition-time reference frame: at AudioContext time `_rateAnchorCtx`,
@@ -53,14 +54,21 @@ export class WebAudioTransport {
const src = el.currentSrc || el.getAttribute("src");
if (!src) return null;
if (this._bufferCache.has(src)) return this._bufferCache.get(src)!;
if (this._failedSrcs.has(src)) return null;
if (!this._ctx) return null;
try {
const response = await fetch(src);
if (!response.ok) {
this._failedSrcs.add(src);
swallow("webAudioTransport.fetch", new Error(`${response.status} ${src}`));
return null;
}
const arrayBuffer = await response.arrayBuffer();
const audioBuffer = await this._ctx.decodeAudioData(arrayBuffer);
this._bufferCache.set(src, audioBuffer);
return audioBuffer;
} catch (err) {
this._failedSrcs.add(src);
swallow("webAudioTransport.decode", err);
return null;
}