@flemo/devtools 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +113 -298
- package/dist/__tests__/hud.test.d.ts +1 -0
- package/dist/__tests__/imageProbe.test.d.ts +1 -0
- package/dist/__tests__/morphProbe.test.d.ts +1 -0
- package/dist/__tests__/persistence.test.d.ts +1 -0
- package/dist/__tests__/preconditions.test.d.ts +1 -0
- package/dist/__tests__/recorder.session.test.d.ts +1 -0
- package/dist/__tests__/tripwires.test.d.ts +1 -0
- package/dist/__tests__/verdict.test.d.ts +1 -0
- package/dist/anomalies.d.ts +3 -2
- package/dist/buckets.d.ts +2 -0
- package/dist/domProtocol.d.ts +22 -0
- package/dist/environment.d.ts +4 -1
- package/dist/flight.d.ts +40 -0
- package/dist/frameProbe.d.ts +53 -0
- package/dist/hud.d.ts +18 -0
- package/dist/imageProbe.d.ts +23 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.mjs +1180 -671
- package/dist/landingProbe.d.ts +17 -0
- package/dist/morphProbe.d.ts +57 -0
- package/dist/noop.d.ts +11 -2
- package/dist/noop.mjs +373 -134
- package/dist/overrides.d.ts +6 -1
- package/dist/panel/index.d.ts +2 -0
- package/dist/panel/styles.d.ts +1 -1
- package/dist/persistence.d.ts +20 -0
- package/dist/preconditions.d.ts +14 -0
- package/dist/recorder.d.ts +4 -1
- package/dist/sampling.d.ts +9 -11
- package/dist/surface.d.ts +30 -0
- package/dist/tripwires.d.ts +37 -0
- package/dist/types.d.ts +213 -16
- package/dist/verdict.d.ts +7 -0
- package/package.json +7 -7
- /package/dist/__tests__/{overridesRegistry.test.d.ts → buckets.test.d.ts} +0 -0
package/dist/noop.mjs
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
//#region src/anomalies.ts
|
|
2
2
|
var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
3
|
-
let n = [], { t0Ms: r, driver: i, frameSamples: a,
|
|
4
|
-
if (
|
|
3
|
+
let n = [], { t0Ms: r, driver: i, frameSamples: a, longTasks: o, holdLongTasks: s, landing: c } = e, l = r + (e.releasedAtMs ?? 0);
|
|
4
|
+
if (a.released.over30Count > 0) {
|
|
5
5
|
let e = i === "compiled" ? " (compiled/compositor flights can still present cleanly through main-thread gaps)" : "";
|
|
6
6
|
n.push(`main-thread rAF gap up to ${a.released.maxGapMs}ms ×${a.released.over30Count} during visible motion${e}`);
|
|
7
7
|
}
|
|
8
|
-
for (let e of
|
|
9
|
-
for (let e of
|
|
10
|
-
let { motion:
|
|
11
|
-
|
|
8
|
+
for (let e of o) e.startMs <= l + 120 && e.startMs + e.durationMs >= l - 50 ? n.push(`long task ${Math.round(e.durationMs)}ms overlapped the visible-motion start (opening-swallow risk: the first presented frames of the transition may have been lost)`) : e.durationMs >= 100 && n.push(`long task ${Math.round(e.durationMs)}ms mid-flight`);
|
|
9
|
+
for (let e of s) e.durationMs >= 100 && n.push(`long task ${Math.round(e.durationMs)}ms absorbed by the hold (screen posed, not yet moving — the hold doing its job, not user-visible jank)`);
|
|
10
|
+
let { motion: u, images: d } = e;
|
|
11
|
+
u.holdReassertedAtMs !== null && n.push(`hold re-asserted ${u.holdReassertedAtMs}ms into the flight, after it had already released (an interleaved commit wrote the stale paused hold attribute over a running flight — the flemo 2026-08-18 release-race signature; the motion pauses while every timing metric stays clean)`), u.pausedAfterRelease && n.push("compiled animation reported playState=paused after its release (the flight was posed and then stopped mid-motion, not merely starved of frames)"), u.longestStallMs >= 48 && n.push(`motion stalled ${u.longestStallMs}ms mid-flight (${u.stalledFrames}/${u.sampledFrames} released frames advanced neither the animation clock nor the pose — freeze, or freeze-then-leap if the flight still landed on time)`), u.sampledFrames === 0 && e.releasedAtMs !== null && n.push("no released frames were sampled (the flight ended at or before its own hold release — the visible motion, if any, was never observed)"), d.completedUnheld > 0 && n.push(`${d.completedUnheld} image(s) finished loading mid-flight without a hold (${d.completedDuringFlight} completed, ${d.heldDuringFlight} held; ${d.loadingAtStart} were loading at t0, ${d.addedDuringFlight} arrived mid-flight) — each decode rasters on the moving layer and costs a present; this is the warm-side image-hold regression`), c.orphanedHolds.length > 0 && n.push(`hold markers left on the page at rest: ${c.orphanedHolds.join("; ")} (whatever they hide has no owner left to reveal it — the permanently-blank-avatar class)`), c.residualInlineTransforms.length > 0 && n.push(`residual inline style after COMPLETED: ${c.residualInlineTransforms.join("; ")} (landing cleanup failure — the landed scope belongs to the compiled rest rules)`), c.offViewportAtRest && n.push("screen resting at from-pose while COMPLETED+active (blank-viewport signature — the flemo PR #259 class: a residual pose left the landed screen parked off-viewport)"), c.stuckStatuses.length > 0 && n.push(`transitional status stuck >${t / 1e3}s: ${c.stuckStatuses.join(", ")} (navigation queue lock or missed animationend — later navigations will be swallowed)`);
|
|
12
|
+
let { morphs: f, tripwires: p } = e;
|
|
13
|
+
for (let e of p) n.push(`tripwire ${e.kind} at +${e.atMs}ms: ${e.detail}`);
|
|
14
|
+
return f.skipped.length > 0 && n.push(`shared element(s) did not fly: ${f.skipped.join(", ")} (${f.pairable.length} pairable key(s), ${f.flew.length} flew) — both ends were registered on two different screens and neither was stamped with a flight role, so the pair was never made`), f.duplicatedKeys.length > 0 && n.push(`pairing key(s) used twice inside one screen: ${f.duplicatedKeys.join(", ")} (two ends under one screen are not a pair, so one of them can never fly — this is in the consuming app)`), f.strandedRoles > 0 && n.push(`${f.strandedRoles} morph element(s) still carry a flight role at rest (the stranded participant class: a role that outlives its flight stays in the layer and poisons the NEXT pairing, which is how one interrupted gesture turned into every later pop losing its camera)`), (f.strandedStandIns > 0 || f.strandedGhosts > 0 || f.layerResidue > 0) && n.push(`morph residue at rest: ${f.strandedStandIns} stand-in(s), ${f.strandedGhosts} ghost(s), ${f.layerResidue} element(s) left in a flight layer (a stand-in is a hole in the layout and a layer element is a corpse the next flight will pair against)`), f.leakedSheetRules > 0 && n.push(`${f.leakedSheetRules} morph keyframe rule(s) were left in the per-flight sheet (a flight that never landed keeps its keyframes; they accumulate for the life of the page)`), i === "unknown" && n.push("driver could not be classified (no running flemo-* CSSAnimation and no player inline-style signature observed — zero-duration flight, or the sampler attached after motion ended)"), n;
|
|
12
15
|
}, s = (e) => {
|
|
13
16
|
let n = [];
|
|
14
17
|
if (e.emulationSuspected) {
|
|
@@ -21,24 +24,48 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
21
24
|
"Display-hardware effects: local dimming, backlight modulation, and panel overdrive alter perceived motion and are invisible to every web API.",
|
|
22
25
|
"Compositor-internal present skips: a frame can be produced on time (clean rAF, clean player gaps) yet dropped or delayed inside the compositor's present queue; only platform tools (about:tracing, Instruments) see that layer.",
|
|
23
26
|
"DevTools device emulation composites the page to a rescaled surface: every in-page instrument reads the pre-scale surface and reports clean while the eye watches the post-scale one, so emulated sessions grow shimmer/flash artifacts that do not exist in a plain window or on a real device."
|
|
24
|
-
], l = () => {
|
|
27
|
+
], l = (e) => {
|
|
28
|
+
/* v8 ignore next -- unreachable: a group exists only because a flight was
|
|
29
|
+
put in it, so nothing ever asks for the median of nothing. */
|
|
30
|
+
if (e.length === 0) return 0;
|
|
31
|
+
let t = [...e].sort((e, t) => e - t);
|
|
32
|
+
return Math.round(t[Math.floor(t.length / 2)] * 10) / 10;
|
|
33
|
+
}, u = (e) => {
|
|
34
|
+
let t = e.filter((e) => typeof e.bucket == "string");
|
|
35
|
+
if (t.length === 0) return [];
|
|
36
|
+
let n = /* @__PURE__ */ new Map();
|
|
37
|
+
for (let e of t) {
|
|
38
|
+
let t = e.bucket, r = n.get(t);
|
|
39
|
+
r ? r.push(e) : n.set(t, [e]);
|
|
40
|
+
}
|
|
41
|
+
return [...n.entries()].map(([e, t]) => ({
|
|
42
|
+
bucket: e,
|
|
43
|
+
flights: t.length,
|
|
44
|
+
medianDurationMs: l(t.map((e) => e.durationMs)),
|
|
45
|
+
medianReleasedGapMs: l(t.map((e) => e.frameSamples.released.medianGapMs)),
|
|
46
|
+
worstReleasedGapMs: t.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0),
|
|
47
|
+
longGapCount: t.reduce((e, t) => e + t.frameSamples.released.over30Count, 0),
|
|
48
|
+
anomalyCount: t.reduce((e, t) => e + t.anomalies.length, 0),
|
|
49
|
+
stalledFlights: t.filter((e) => e.motion.stalledFrames > 0).length
|
|
50
|
+
})).sort((e, t) => e.bucket.localeCompare(t.bucket));
|
|
51
|
+
}, d = () => {
|
|
25
52
|
if (typeof navigator > "u") return null;
|
|
26
53
|
let e = navigator.userAgentData;
|
|
27
54
|
return !e || !Array.isArray(e.brands) ? null : e.brands.map((e) => ({
|
|
28
55
|
brand: String(e.brand ?? ""),
|
|
29
56
|
version: String(e.version ?? "")
|
|
30
57
|
}));
|
|
31
|
-
},
|
|
58
|
+
}, f = () => {
|
|
32
59
|
if (typeof navigator > "u") return "unknown";
|
|
33
|
-
let e =
|
|
60
|
+
let e = d();
|
|
34
61
|
if (e?.some((e) => /Chromium/i.test(e.brand))) return "blink";
|
|
35
62
|
let t = navigator.userAgent ?? "";
|
|
36
63
|
return /Firefox|FxiOS/i.test(t) ? "gecko" : e || /AppleWebKit/i.test(t) && !/Chrome|Chromium|Android/i.test(t) ? "webkit" : /Android/i.test(t) ? "blink" : "unknown";
|
|
37
|
-
},
|
|
38
|
-
if (typeof navigator > "u" ||
|
|
64
|
+
}, p = () => {
|
|
65
|
+
if (typeof navigator > "u" || f() !== "blink") return !1;
|
|
39
66
|
let e = navigator.platform ?? "";
|
|
40
67
|
return /Mac|Win|Linux/i.test(e) ? /Android/i.test(navigator.userAgent ?? "") && !/Mac|Win/i.test(e) ? /Linux (x86_64|i686)/i.test(e) : (navigator.maxTouchPoints ?? 0) > 0 : !1;
|
|
41
|
-
},
|
|
68
|
+
}, m = (e = 20) => new Promise((t) => {
|
|
42
69
|
let n = Number.isFinite(e) ? Math.max(1, Math.floor(e)) : 20;
|
|
43
70
|
if (typeof requestAnimationFrame != "function" || typeof performance > "u") {
|
|
44
71
|
t({
|
|
@@ -60,45 +87,68 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
60
87
|
requestAnimationFrame(a);
|
|
61
88
|
};
|
|
62
89
|
requestAnimationFrame(a);
|
|
63
|
-
}),
|
|
90
|
+
}), h = [
|
|
91
|
+
"__vite_plugin_react_preamble_installed__",
|
|
92
|
+
"__vite__",
|
|
93
|
+
"__NEXT_HMR_CB",
|
|
94
|
+
"__NEXT_HMR_LATENCY_CB",
|
|
95
|
+
"__webpack_hot_middleware_reporter__",
|
|
96
|
+
"webpackHotUpdate",
|
|
97
|
+
"__REACT_REFRESH_RUNTIME__",
|
|
98
|
+
"$RefreshReg$"
|
|
99
|
+
], g = () => {
|
|
100
|
+
if (typeof window > "u") return [];
|
|
101
|
+
let e = [];
|
|
102
|
+
for (let t of h) try {
|
|
103
|
+
window[t] !== void 0 && e.push(t);
|
|
104
|
+
} catch {}
|
|
105
|
+
return e;
|
|
106
|
+
}, _ = () => {
|
|
64
107
|
try {
|
|
65
108
|
return typeof PerformanceObserver < "u" && Array.isArray(PerformanceObserver.supportedEntryTypes) && PerformanceObserver.supportedEntryTypes.includes("longtask");
|
|
66
109
|
} catch {
|
|
67
110
|
return !1;
|
|
68
111
|
}
|
|
69
|
-
},
|
|
70
|
-
let
|
|
112
|
+
}, v = (e, t = !1) => {
|
|
113
|
+
let n = typeof navigator < "u" ? navigator : null, r = typeof window < "u" ? window : null, i = !1;
|
|
71
114
|
try {
|
|
72
|
-
|
|
115
|
+
i = r?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? !1;
|
|
73
116
|
} catch {
|
|
74
|
-
|
|
117
|
+
i = !1;
|
|
75
118
|
}
|
|
76
119
|
return {
|
|
77
|
-
userAgent:
|
|
78
|
-
uaBrands:
|
|
79
|
-
engine:
|
|
80
|
-
platform:
|
|
81
|
-
maxTouchPoints:
|
|
82
|
-
devicePixelRatio:
|
|
120
|
+
userAgent: n?.userAgent ?? "",
|
|
121
|
+
uaBrands: d(),
|
|
122
|
+
engine: f(),
|
|
123
|
+
platform: n?.platform ?? "",
|
|
124
|
+
maxTouchPoints: n?.maxTouchPoints ?? 0,
|
|
125
|
+
devicePixelRatio: r?.devicePixelRatio ?? 1,
|
|
126
|
+
hardwareConcurrency: n?.hardwareConcurrency ?? 0,
|
|
83
127
|
screen: {
|
|
84
|
-
width:
|
|
85
|
-
height:
|
|
128
|
+
width: r?.screen?.width ?? 0,
|
|
129
|
+
height: r?.screen?.height ?? 0
|
|
86
130
|
},
|
|
87
131
|
viewport: {
|
|
88
|
-
width:
|
|
89
|
-
height:
|
|
132
|
+
width: r?.innerWidth ?? 0,
|
|
133
|
+
height: r?.innerHeight ?? 0
|
|
90
134
|
},
|
|
91
|
-
visualViewportScale:
|
|
135
|
+
visualViewportScale: r?.visualViewport?.scale ?? null,
|
|
92
136
|
rafCadence: e,
|
|
93
|
-
reducedMotion:
|
|
94
|
-
|
|
137
|
+
reducedMotion: i,
|
|
138
|
+
developmentHints: g(),
|
|
139
|
+
emulationSuspected: p(),
|
|
95
140
|
observation: {
|
|
96
|
-
longTasks:
|
|
141
|
+
longTasks: _(),
|
|
97
142
|
elementAnimations: typeof Element < "u" && typeof Element.prototype.getAnimations == "function",
|
|
98
|
-
|
|
143
|
+
animationEvents: t
|
|
99
144
|
}
|
|
100
145
|
};
|
|
101
|
-
},
|
|
146
|
+
}, y = [
|
|
147
|
+
"DevTools must be CLOSED while judging motion. An open inspector serializes requests and repaints its own panels on the same machine; the 2026-08 campaign's entire residual 'stutter' was this, and it is invisible to every in-page metric.",
|
|
148
|
+
"No screen recording or display capture while judging. A capture client forces WindowServer to composite every vsync, which SUPPRESSES the symptom — a capture that looks smooth proves nothing about the uncaptured session.",
|
|
149
|
+
"Judge with real input (a finger, a mouse). Synthetic dispatch — evaluate().click() and friends — never fires pointerdown, so it bypasses the swipe/gesture machinery that a real navigation goes through.",
|
|
150
|
+
"Establish the viewing configuration before believing any verdict: device emulation off, which physical display, its refresh rate and HiDPI scaling, Low Power Mode. Ask for a photo of the setup if it is not certain."
|
|
151
|
+
], b = "flemo:devtools-panel-height", x = [{
|
|
102
152
|
key: "flemo:devtools",
|
|
103
153
|
storage: "session",
|
|
104
154
|
kind: "opt-in-diagnostic",
|
|
@@ -106,118 +156,88 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
106
156
|
fallback: "off",
|
|
107
157
|
effect: "arms this flight recorder in the playground (?devtools=on)"
|
|
108
158
|
}, {
|
|
109
|
-
key:
|
|
159
|
+
key: b,
|
|
110
160
|
storage: "session",
|
|
111
161
|
kind: "production-state",
|
|
112
162
|
values: "a pixel height",
|
|
113
163
|
fallback: "(the panel's default height)",
|
|
114
164
|
effect: "the drawer height this panel was last dragged to"
|
|
115
|
-
}],
|
|
165
|
+
}], S = [], C = [...S, ...x], w = [
|
|
116
166
|
{
|
|
117
167
|
key: "flemo:sixty",
|
|
118
168
|
storage: "session",
|
|
119
|
-
|
|
120
|
-
values: "\"high\" / a streak count",
|
|
121
|
-
fallback: "(learned)",
|
|
122
|
-
effect: "steady-60 desktop verdict seed — owned by steadySixtyCadence.ts"
|
|
169
|
+
retiredWith: "the steady-60 verdict seed, now document-scoped module state (2026-08-31)"
|
|
123
170
|
},
|
|
124
171
|
{
|
|
125
172
|
key: "flemo:settle-gate",
|
|
126
173
|
storage: "session",
|
|
127
|
-
|
|
128
|
-
values: "\"on\" / \"off\"",
|
|
129
|
-
fallback: "touch WebKit + touch Blink + desktop macOS WebKit + steady-60 desktop",
|
|
130
|
-
effect: "render-settle entry gate, shared by the engine's routing and the binding"
|
|
174
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
131
175
|
},
|
|
132
176
|
{
|
|
133
177
|
key: "flemo:arrivalhold",
|
|
134
178
|
storage: "session",
|
|
135
|
-
|
|
136
|
-
values: "\"off\"",
|
|
137
|
-
fallback: "on",
|
|
138
|
-
effect: "the whole in-flight hold set (arrival, response, invisible animations, images)"
|
|
179
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
139
180
|
},
|
|
140
181
|
{
|
|
141
182
|
key: "flemo:deskflip",
|
|
142
183
|
storage: "session",
|
|
143
|
-
|
|
144
|
-
values: "\"on\" / \"off\"",
|
|
145
|
-
fallback: "desktop macOS WebKit",
|
|
146
|
-
effect: "atomic release flip: the hold attribute flips on the DOM inside the readiness rAF"
|
|
184
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
147
185
|
},
|
|
148
186
|
{
|
|
149
187
|
key: "flemo:deskhead",
|
|
150
188
|
storage: "session",
|
|
151
|
-
|
|
152
|
-
values: "\"on\" / \"off\"",
|
|
153
|
-
fallback: "desktop macOS WebKit",
|
|
154
|
-
effect: "desktop flat-head keyframes; arming it retires the desktop birth anchor"
|
|
189
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
155
190
|
},
|
|
156
191
|
{
|
|
157
192
|
key: "flemo:creep",
|
|
158
193
|
storage: "session",
|
|
159
|
-
|
|
160
|
-
values: "\"on\" / \"off\"",
|
|
161
|
-
fallback: "touch WebKit",
|
|
162
|
-
effect: "creep head: its end keyframe carries a hair of motion, so the compositor is already carrying the animation at the boundary"
|
|
194
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
163
195
|
},
|
|
164
196
|
{
|
|
165
197
|
key: "flemo:relcommit",
|
|
166
198
|
storage: "session",
|
|
167
|
-
|
|
168
|
-
values: "\"defer\" / \"sync\"",
|
|
169
|
-
fallback: "touch WebKit",
|
|
170
|
-
effect: "the release's reconcile lands next frame instead of synchronously"
|
|
199
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
171
200
|
},
|
|
172
201
|
{
|
|
173
202
|
key: "flemo:imgoffload",
|
|
174
203
|
storage: "session",
|
|
175
|
-
|
|
176
|
-
values: "\"on\" / \"off\"",
|
|
177
|
-
fallback: "on — the offloader decides per image, from the source's own size",
|
|
178
|
-
effect: "image decode offloader: an oversized source is fetched and downscaled in a worker so its decode never lands in a paint"
|
|
204
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
179
205
|
},
|
|
180
206
|
{
|
|
181
207
|
key: "flemo:governed",
|
|
182
208
|
storage: "session",
|
|
183
|
-
|
|
184
|
-
values: "\"on\" / \"off\"",
|
|
185
|
-
fallback: "legacy Android Blink (an old browser, not a slow device)",
|
|
186
|
-
effect: "the governed head kit on touch Blink — a flat head covering a compiled flight's opening. The auto-detection reads browser AGE, so a modern-but-weak phone falls through it; this is how such a device gets measured"
|
|
209
|
+
retiredWith: "the engine diagnostic surface (2026-08-31)"
|
|
187
210
|
},
|
|
188
211
|
{
|
|
189
212
|
key: "flemo:imghold",
|
|
190
213
|
storage: "session",
|
|
191
|
-
|
|
192
|
-
values: "\"on\" / \"off\"",
|
|
193
|
-
fallback: "off",
|
|
194
|
-
effect: "flight-scoped <img> reveal hold"
|
|
214
|
+
retiredWith: "the image reveal hold, whose only arming path it was (2026-08-31)"
|
|
195
215
|
},
|
|
196
216
|
{
|
|
197
217
|
key: "flemo:preraster",
|
|
198
218
|
storage: "session",
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
219
|
+
retiredWith: "the REST-time scope promotion, whose only arming path it was (2026-08-31)"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
key: "flemo:parkhead",
|
|
223
|
+
storage: "session",
|
|
224
|
+
retiredWith: "the engine diagnostic surface — the park head is unconditional (2026-08-31)"
|
|
203
225
|
},
|
|
204
226
|
{
|
|
205
227
|
key: "flemo:layers",
|
|
206
228
|
storage: "session",
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
229
|
+
retiredWith: "the resident-layer experiment (2026-08-31)"
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
key: "flemo:morph",
|
|
233
|
+
storage: "session",
|
|
234
|
+
retiredWith: "the morph decision trace (2026-08-31)"
|
|
211
235
|
},
|
|
212
236
|
{
|
|
213
237
|
key: "flemo:freeze",
|
|
214
238
|
storage: "session",
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
fallback: "off",
|
|
218
|
-
effect: "keep the direct prev screen live instead of freezing it"
|
|
219
|
-
}
|
|
220
|
-
], v = [..._, ...g], y = [
|
|
239
|
+
retiredWith: "the shallow-freeze experiment (2026-08-31)"
|
|
240
|
+
},
|
|
221
241
|
{
|
|
222
242
|
key: "flemo:motion-driver",
|
|
223
243
|
storage: "local",
|
|
@@ -263,49 +283,237 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
263
283
|
storage: "session",
|
|
264
284
|
retiredWith: "the Low Power Mode release-latency probe (2026-08-22)"
|
|
265
285
|
}
|
|
266
|
-
],
|
|
286
|
+
], T = "(retired — the library no longer reads this)", E = (e) => {
|
|
267
287
|
try {
|
|
268
288
|
let t = e === "session" ? sessionStorage : localStorage;
|
|
269
289
|
return t.length, t;
|
|
270
290
|
} catch {
|
|
271
291
|
return null;
|
|
272
292
|
}
|
|
273
|
-
},
|
|
293
|
+
}, D = (e, t) => {
|
|
274
294
|
try {
|
|
275
295
|
return e ? e.getItem(t) : null;
|
|
276
296
|
} catch {
|
|
277
297
|
return null;
|
|
278
298
|
}
|
|
279
|
-
},
|
|
280
|
-
let e = {}, t =
|
|
281
|
-
for (let r of
|
|
282
|
-
let i =
|
|
299
|
+
}, ee = new Set(C.map((e) => e.key)), te = new Set(w.map((e) => e.key)), ne = () => {
|
|
300
|
+
let e = {}, t = E("session"), n = E("local");
|
|
301
|
+
for (let r of C) {
|
|
302
|
+
let i = D(r.storage === "session" ? t : n, r.key);
|
|
283
303
|
i !== null && (e[r.key] = i);
|
|
284
304
|
}
|
|
285
|
-
for (let r of
|
|
286
|
-
let t =
|
|
287
|
-
t !== null && (e[`${r.key} (${a}) ${
|
|
305
|
+
for (let r of w) for (let [i, a] of [[t, "sessionStorage"], [n, "localStorage"]]) {
|
|
306
|
+
let t = D(i, r.key);
|
|
307
|
+
t !== null && (e[`${r.key} (${a}) ${T}`] = t);
|
|
288
308
|
}
|
|
289
309
|
for (let [r, i] of [[t, "sessionStorage"], [n, "localStorage"]]) if (r) try {
|
|
290
310
|
for (let t = 0; t < r.length; t += 1) {
|
|
291
311
|
let n = r.key(t);
|
|
292
|
-
!n || !n.startsWith("flemo:") ||
|
|
312
|
+
!n || !n.startsWith("flemo:") || ee.has(n) || te.has(n) || (e[`${n} (${i}, unknown key)`] = r.getItem(n) ?? "");
|
|
293
313
|
}
|
|
294
314
|
} catch {}
|
|
295
315
|
return e;
|
|
296
|
-
},
|
|
316
|
+
}, O = (e) => {
|
|
297
317
|
let t = [];
|
|
298
|
-
for (let [n, r] of Object.entries(e)) {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
let e = v.find((e) => n === e.key || n.startsWith(`${e.key} `));
|
|
305
|
-
!e || T.has(e.key) || (e.kind === "opt-in-diagnostic" ? t.push(`${n}=${r} — opt-in diagnostic active (${e.effect}); behavior differs from stock. Possible left-over A/B toggle from an earlier debugging session.`) : e.kind === "production-default-with-override" && t.push(`${n}=${r} — production default overridden for this session (${e.effect}). Stock behavior here is ${e.fallback}.`));
|
|
318
|
+
for (let [n, r] of Object.entries(e)) if (n.includes("(retired — the library no longer reads this)")) {
|
|
319
|
+
let e = n.slice(0, n.indexOf(" (")), i = w.find((t) => t.key === e);
|
|
320
|
+
t.push(`${n}=${r} — RETIRED residue: this key went with ${i?.retiredWith ?? "a removed feature"}. The library never reads it, so it cannot explain anything you are seeing. Safe to delete; it is listed only so it does not read as an unexplained lead.`);
|
|
321
|
+
continue;
|
|
306
322
|
}
|
|
307
323
|
return t;
|
|
308
|
-
},
|
|
324
|
+
}, k = "flemo:devtools-trace", A = 10, j = 64e3, M = () => {
|
|
325
|
+
try {
|
|
326
|
+
let e = sessionStorage;
|
|
327
|
+
return e.length, e;
|
|
328
|
+
} catch {
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}, N = (e, t) => {
|
|
332
|
+
let n = M();
|
|
333
|
+
if (!n) return;
|
|
334
|
+
let r = e.slice(-10);
|
|
335
|
+
for (; r.length > 0;) {
|
|
336
|
+
let e = JSON.stringify({
|
|
337
|
+
version: t,
|
|
338
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
339
|
+
flights: r
|
|
340
|
+
});
|
|
341
|
+
if (e.length <= 64e3) {
|
|
342
|
+
try {
|
|
343
|
+
n.setItem(k, e);
|
|
344
|
+
} catch {}
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
r = r.slice(1);
|
|
348
|
+
}
|
|
349
|
+
P();
|
|
350
|
+
}, P = () => {
|
|
351
|
+
try {
|
|
352
|
+
M()?.removeItem(k);
|
|
353
|
+
} catch {}
|
|
354
|
+
}, F = (e) => {
|
|
355
|
+
let t = M();
|
|
356
|
+
if (!t) return null;
|
|
357
|
+
let n = null;
|
|
358
|
+
try {
|
|
359
|
+
n = t.getItem(k);
|
|
360
|
+
} catch {
|
|
361
|
+
return null;
|
|
362
|
+
}
|
|
363
|
+
if (n === null) return null;
|
|
364
|
+
let r = null;
|
|
365
|
+
try {
|
|
366
|
+
r = JSON.parse(n);
|
|
367
|
+
} catch {
|
|
368
|
+
return P(), null;
|
|
369
|
+
}
|
|
370
|
+
return !r || r.version !== e || !Array.isArray(r.flights) ? (P(), null) : {
|
|
371
|
+
savedAt: typeof r.savedAt == "string" ? r.savedAt : "",
|
|
372
|
+
flights: r.flights,
|
|
373
|
+
note: "These flights were recorded by the page instance BEFORE the last full load. They are kept apart from the live ones because they may have come from a different build."
|
|
374
|
+
};
|
|
375
|
+
}, I = 12, L = 20, R = 40, z = 500, B = 200, V = (e) => {
|
|
376
|
+
let t = e.rafCadence.medianGapMs;
|
|
377
|
+
if (t === null) return {
|
|
378
|
+
id: "display-cadence",
|
|
379
|
+
status: "unknown",
|
|
380
|
+
detail: "the idle frame cadence could not be sampled, so the display's rate is unknown"
|
|
381
|
+
};
|
|
382
|
+
let n = { medianIdleFrameMs: t };
|
|
383
|
+
return t < I ? {
|
|
384
|
+
id: "display-cadence",
|
|
385
|
+
status: "ok",
|
|
386
|
+
detail: `idle frames arrive every ${t}ms — a display above 60Hz. Frame budgets in this report are still quoted against 60Hz (a gap of 30ms or more)`,
|
|
387
|
+
metrics: n
|
|
388
|
+
} : t <= L ? {
|
|
389
|
+
id: "display-cadence",
|
|
390
|
+
status: "ok",
|
|
391
|
+
detail: `idle frames arrive every ${t}ms — a 60Hz clock`,
|
|
392
|
+
metrics: n
|
|
393
|
+
} : t <= R ? {
|
|
394
|
+
id: "display-cadence",
|
|
395
|
+
status: "violated",
|
|
396
|
+
detail: `idle frames arrive every ${t}ms — the page is being served roughly HALF rate. On iOS this is Low Power Mode, whose main-thread ceiling is ~30Hz while the compositor keeps 60: motion judged here is judged against a clock no transition can beat, and the ceiling is not a library defect. Turn it off, or judge elsewhere`,
|
|
397
|
+
metrics: n
|
|
398
|
+
} : {
|
|
399
|
+
id: "display-cadence",
|
|
400
|
+
status: "violated",
|
|
401
|
+
detail: `idle frames arrive every ${t}ms — the page is barely being served frames at all while idle. Something outside the transition owns this machine; no motion verdict taken here means anything`,
|
|
402
|
+
metrics: n
|
|
403
|
+
};
|
|
404
|
+
}, H = (e) => {
|
|
405
|
+
if (!e.environment.observation.longTasks) return {
|
|
406
|
+
id: "machine-idle",
|
|
407
|
+
status: "unknown",
|
|
408
|
+
detail: "this browser does not report long tasks, so the recorder cannot tell whether anything else was competing for the main thread"
|
|
409
|
+
};
|
|
410
|
+
let t = e.idleLongTasks.length, n = Math.round(e.idleLongTasks.reduce((e, t) => e + t.durationMs, 0)), r = Math.round(e.idleLongTasks.reduce((e, t) => Math.max(e, t.durationMs), 0)), i = {
|
|
411
|
+
idleLongTasks: t,
|
|
412
|
+
idleLongTaskMs: n,
|
|
413
|
+
worstIdleTaskMs: r
|
|
414
|
+
};
|
|
415
|
+
return n >= z || r >= B ? {
|
|
416
|
+
id: "machine-idle",
|
|
417
|
+
status: "violated",
|
|
418
|
+
detail: `${t} long task(s) totalling ${n}ms ran while NO navigation was in flight (worst ${r}ms). Something else on this page or this machine was busy, and a motion verdict taken under someone else's load measures the load. A whole tremble campaign was invalidated by exactly this, with a build running in another window`,
|
|
419
|
+
metrics: i
|
|
420
|
+
} : {
|
|
421
|
+
id: "machine-idle",
|
|
422
|
+
status: "ok",
|
|
423
|
+
detail: `${t} idle long task(s), ${n}ms total — the page was quiet between navigations`,
|
|
424
|
+
metrics: i
|
|
425
|
+
};
|
|
426
|
+
}, U = (e) => {
|
|
427
|
+
let { trusted: t, synthetic: n, pointerTypes: r } = e.input;
|
|
428
|
+
return n > 0 ? {
|
|
429
|
+
id: "real-input",
|
|
430
|
+
status: "violated",
|
|
431
|
+
detail: `${n} script-dispatched (untrusted) input event(s) drove this session. Synthetic dispatch never fires the gesture machinery a real navigation goes through, so a clean run proves nothing about a finger`,
|
|
432
|
+
metrics: {
|
|
433
|
+
trusted: t,
|
|
434
|
+
synthetic: n
|
|
435
|
+
}
|
|
436
|
+
} : t === 0 ? {
|
|
437
|
+
id: "real-input",
|
|
438
|
+
status: "unknown",
|
|
439
|
+
detail: "no input event preceded any recorded flight. These navigations were driven programmatically or by the browser's own back/forward, which is a different path from the one a user takes",
|
|
440
|
+
metrics: {
|
|
441
|
+
trusted: t,
|
|
442
|
+
synthetic: n
|
|
443
|
+
}
|
|
444
|
+
} : {
|
|
445
|
+
id: "real-input",
|
|
446
|
+
status: "ok",
|
|
447
|
+
detail: `${t} trusted input event(s) drove this session (${r.join(", ") || "type unreported"})`,
|
|
448
|
+
metrics: {
|
|
449
|
+
trusted: t,
|
|
450
|
+
synthetic: n
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
}, re = (e) => e.input.pointerTypes.includes("touch") ? {
|
|
454
|
+
id: "touch-path",
|
|
455
|
+
status: "ok",
|
|
456
|
+
detail: "at least one navigation was driven by touch"
|
|
457
|
+
} : e.environment.maxTouchPoints === 0 ? {
|
|
458
|
+
id: "touch-path",
|
|
459
|
+
status: "unknown",
|
|
460
|
+
detail: "this device reports no touch points, so there is no touch path to exercise here"
|
|
461
|
+
} : {
|
|
462
|
+
id: "touch-path",
|
|
463
|
+
status: "unknown",
|
|
464
|
+
detail: "no touch-driven navigation was recorded on a touch-capable device. The swipe and pointer-capture paths are only reached by a finger; a build that had broken them outright once passed every automated layer green because every probe used a mouse"
|
|
465
|
+
}, W = [
|
|
466
|
+
{
|
|
467
|
+
id: "devtools-closed",
|
|
468
|
+
status: "unknown",
|
|
469
|
+
detail: "whether an inspector is open cannot be seen from inside the page. An open one serializes requests and repaints its own panels on the same machine; a whole campaign's residual stutter was this and nothing else. Confirm it with the user"
|
|
470
|
+
},
|
|
471
|
+
{
|
|
472
|
+
id: "no-screen-capture",
|
|
473
|
+
status: "unknown",
|
|
474
|
+
detail: "whether the screen is being captured cannot be seen from inside the page. A capture client forces the compositor to present every vsync, which SUPPRESSES the symptom — a recording that looks smooth proves nothing about the uncaptured session"
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
id: "viewing-configuration",
|
|
478
|
+
status: "unknown",
|
|
479
|
+
detail: "which physical display this window is on, its refresh rate and scaling, cannot be read from the page. Establish it with the user before believing any verdict"
|
|
480
|
+
}
|
|
481
|
+
], G = (e) => {
|
|
482
|
+
let { environment: t } = e, n = [];
|
|
483
|
+
return n.push(t.emulationSuspected ? {
|
|
484
|
+
id: "device-emulation",
|
|
485
|
+
status: "violated",
|
|
486
|
+
detail: "DevTools device emulation is suspected (Blink on a desktop platform reporting touch points). Emulation composites the page to a rescaled surface: every in-page instrument reads the pre-scale surface and reports clean while the eye watches the post-scale one" + (/Win/i.test(t.platform) ? ". Windows touch hardware makes this signal ambiguous — confirm the device toolbar state" : "")
|
|
487
|
+
} : {
|
|
488
|
+
id: "device-emulation",
|
|
489
|
+
status: "ok",
|
|
490
|
+
detail: "no device-emulation signature on this session"
|
|
491
|
+
}), n.push(V(t)), n.push(e.documentHidden || e.wentHidden ? {
|
|
492
|
+
id: "page-foreground",
|
|
493
|
+
status: "violated",
|
|
494
|
+
detail: e.documentHidden ? "this document is HIDDEN right now — a backgrounded page is throttled to a fraction of its frames" : "this document was hidden at least once while recording; any flight that ran then was throttled"
|
|
495
|
+
} : {
|
|
496
|
+
id: "page-foreground",
|
|
497
|
+
status: "ok",
|
|
498
|
+
detail: "the document stayed visible throughout"
|
|
499
|
+
}), n.push(H(e)), n.push(t.developmentHints.length > 0 ? {
|
|
500
|
+
id: "build-mode",
|
|
501
|
+
status: "violated",
|
|
502
|
+
detail: `development-server globals are present (${t.developmentHints.join(", ")}). A development build is a different program: unminified, double-invoking, and hot-reload instrumented. A day of ladder measurements once turned out to be measuring the build itself`
|
|
503
|
+
} : {
|
|
504
|
+
id: "build-mode",
|
|
505
|
+
status: "unknown",
|
|
506
|
+
detail: "no development-server global was found. That is consistent with a production build but does not prove one — confirm how this page was built"
|
|
507
|
+
}), n.push(U(e)), n.push(re(e)), n.push(t.reducedMotion ? {
|
|
508
|
+
id: "reduced-motion",
|
|
509
|
+
status: "violated",
|
|
510
|
+
detail: "this session prefers reduced motion, so the transitions under test are being suppressed or shortened. Whatever is on screen is not the motion being judged"
|
|
511
|
+
} : {
|
|
512
|
+
id: "reduced-motion",
|
|
513
|
+
status: "ok",
|
|
514
|
+
detail: "reduced motion is not requested"
|
|
515
|
+
}), [...n, ...W];
|
|
516
|
+
}, K = (e) => Math.round(e * 10) / 10, q = (e) => {
|
|
309
517
|
if (e.length === 0) return {
|
|
310
518
|
count: 0,
|
|
311
519
|
medianGapMs: 0,
|
|
@@ -315,11 +523,11 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
315
523
|
let t = [...e].sort((e, t) => e - t);
|
|
316
524
|
return {
|
|
317
525
|
count: e.length,
|
|
318
|
-
medianGapMs:
|
|
319
|
-
maxGapMs:
|
|
526
|
+
medianGapMs: K(t[Math.floor(t.length / 2)]),
|
|
527
|
+
maxGapMs: K(t[t.length - 1]),
|
|
320
528
|
over30Count: e.filter((e) => e >= 30).length
|
|
321
529
|
};
|
|
322
|
-
},
|
|
530
|
+
}, J = (e, t = []) => {
|
|
323
531
|
let n = [...e, ...t];
|
|
324
532
|
return {
|
|
325
533
|
...n.length === 0 ? {
|
|
@@ -330,21 +538,18 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
330
538
|
let e = [...n].sort((e, t) => e - t);
|
|
331
539
|
return {
|
|
332
540
|
count: n.length,
|
|
333
|
-
medianGapMs:
|
|
334
|
-
maxGapMs:
|
|
541
|
+
medianGapMs: K(e[Math.floor(e.length / 2)]),
|
|
542
|
+
maxGapMs: K(e[e.length - 1])
|
|
335
543
|
};
|
|
336
544
|
})(),
|
|
337
|
-
longGaps: n.filter((e) => e >= 30).map(
|
|
338
|
-
held:
|
|
339
|
-
released:
|
|
545
|
+
longGaps: n.filter((e) => e >= 30).map(K),
|
|
546
|
+
held: q(e),
|
|
547
|
+
released: q(t)
|
|
340
548
|
};
|
|
341
|
-
},
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
},
|
|
345
|
-
let t = e.playerSuppression || e.playerAdvance;
|
|
346
|
-
return t && e.compiledAnimation ? "mixed" : t ? "player" : e.compiledAnimation ? "compiled" : "unknown";
|
|
347
|
-
}, N = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, P = (e) => {
|
|
549
|
+
}, Y = (e) => {
|
|
550
|
+
let t = e.inlineSuppression || e.inlineAdvance;
|
|
551
|
+
return t && e.compiledAnimation ? "mixed" : t ? "inline" : e.compiledAnimation ? "compiled" : "unknown";
|
|
552
|
+
}, X = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, ie = (e) => {
|
|
348
553
|
let t = /^matrix3d\(([^)]+)\)$/.exec(e.trim());
|
|
349
554
|
if (t) {
|
|
350
555
|
let e = t[1].split(",").map((e) => Number(e.trim()));
|
|
@@ -356,9 +561,37 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
356
561
|
return e.length === 6 && Number.isFinite(e[4]) ? e[4] : null;
|
|
357
562
|
}
|
|
358
563
|
return null;
|
|
359
|
-
},
|
|
564
|
+
}, ae = (e) => {
|
|
565
|
+
/* v8 ignore next -- unreachable: deriveVerdict returns before this on an
|
|
566
|
+
empty flight list, so nothing ever asks for the median of nothing. */
|
|
567
|
+
if (e.length === 0) return 0;
|
|
568
|
+
let t = [...e].sort((e, t) => e - t);
|
|
569
|
+
return t[Math.floor(t.length / 2)];
|
|
570
|
+
}, oe = (e) => {
|
|
571
|
+
let t = [], n = e.preconditions.filter((e) => e.status === "violated");
|
|
572
|
+
if (n.length > 0 && t.push(`NOT EVIDENCE: ${n.length} judging precondition(s) failed — ${n.map((e) => e.id).join(", ")}. Everything below was measured under those conditions; fix them and measure again before drawing a conclusion from it.`), e.flights.length === 0) return t.push("No flights were recorded. Either no navigation happened while the recorder was attached, or it attached after the one you meant to measure — the recorder only sees flights that start after it does."), t;
|
|
573
|
+
e.observation.animationEvents || t.push("The animation channel observed NOTHING across this whole session: not one flemo keyframe reported a start, an end or a cancel, though flights were recorded. Treat every animation-derived field here as unmeasured rather than as clean — a probe that never fires reads exactly like a page with nothing to report.");
|
|
574
|
+
let r = e.flights, i = r.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0), a = r.filter((e) => e.anomalies.length > 0).length;
|
|
575
|
+
t.push(`${r.length} flight(s) recorded. Median duration ${ae(r.map((e) => e.durationMs))}ms, worst frame gap during visible motion ${i}ms, ${a} flight(s) carrying at least one anomaly.`);
|
|
576
|
+
let o = r.filter((e) => e.motion.longestStallMs >= 48);
|
|
577
|
+
o.length > 0 && t.push(`${o.length} flight(s) STOPPED MOVING mid-flight (longest ${Math.max(...o.map((e) => e.motion.longestStallMs))}ms). Frames kept arriving; the picture did not change. Look at the hold and the animation's play state, not at the frame budget.`);
|
|
578
|
+
let s = r.filter((e) => e.morphs.skipped.length > 0);
|
|
579
|
+
if (s.length > 0) {
|
|
580
|
+
let e = [...new Set(s.flatMap((e) => e.morphs.skipped))];
|
|
581
|
+
t.push(`Shared elements did NOT fly on ${s.length} flight(s): ${e.join(", ")}. Both ends were registered on two different screens and neither was ever stamped with a flight role, so the pair was never made. This is silent by nature — nothing else on the page says it happened.`);
|
|
582
|
+
}
|
|
583
|
+
let c = [...new Set(r.flatMap((e) => e.morphs.duplicatedKeys))];
|
|
584
|
+
c.length > 0 && t.push(`Pairing key(s) used twice inside one screen: ${c.join(", ")}. Two ends under one screen are not a pair, so one of them can never fly. This is in the consuming app, not in the library.`);
|
|
585
|
+
let l = r.flatMap((e) => e.tripwires);
|
|
586
|
+
if (l.length > 0) {
|
|
587
|
+
let e = [...new Set(l.map((e) => e.kind))];
|
|
588
|
+
t.push(`${l.length} tripwire hit(s) across the session (${e.join(", ")}). These are one-frame events reported by the browser itself, not sampled — read the flights' \`tripwires\` arrays for the exact animations.`);
|
|
589
|
+
}
|
|
590
|
+
return r.filter((e) => e.frameSamples.released.over30Count > 0).length === 0 && a === 0 && n.length === 0 && t.push("No flight dropped a frame during visible motion (nothing at or over 30ms) and no anomaly fired. Under the preconditions above, this session is clean — what remains is in `blindSpots`, and none of it is reachable from page code."), t;
|
|
591
|
+
}, se = "3", Z = "@flemo/devtools resolved to its production entry: nothing was recorded. Run a development build to collect a real report.", Q = () => {}, ce = () => ({
|
|
360
592
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
361
593
|
version: "inert",
|
|
594
|
+
verdict: [Z],
|
|
362
595
|
environment: {
|
|
363
596
|
userAgent: "",
|
|
364
597
|
uaBrands: null,
|
|
@@ -379,25 +612,31 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
379
612
|
medianGapMs: null,
|
|
380
613
|
sampleCount: 0
|
|
381
614
|
},
|
|
615
|
+
hardwareConcurrency: 0,
|
|
382
616
|
reducedMotion: !1,
|
|
617
|
+
developmentHints: [],
|
|
383
618
|
emulationSuspected: !1,
|
|
384
619
|
observation: {
|
|
385
620
|
longTasks: !1,
|
|
386
621
|
elementAnimations: !1,
|
|
387
|
-
|
|
622
|
+
animationEvents: !1
|
|
388
623
|
}
|
|
389
624
|
},
|
|
625
|
+
preconditions: [],
|
|
390
626
|
overrides: {
|
|
391
627
|
active: {},
|
|
392
|
-
warnings: [
|
|
628
|
+
warnings: [Z]
|
|
393
629
|
},
|
|
394
630
|
flights: [],
|
|
395
|
-
|
|
631
|
+
comparison: [],
|
|
632
|
+
previousSession: null,
|
|
633
|
+
anomalies: [Z],
|
|
396
634
|
blindSpots: [],
|
|
397
|
-
judgingProtocol: [
|
|
398
|
-
}),
|
|
399
|
-
detach:
|
|
400
|
-
report:
|
|
401
|
-
|
|
635
|
+
judgingProtocol: [Z]
|
|
636
|
+
}), le = (e) => ({
|
|
637
|
+
detach: Q,
|
|
638
|
+
report: ce,
|
|
639
|
+
mark: () => null
|
|
640
|
+
}), $ = (e) => ({ detach: Q }), ue = (e) => ({ detach: Q });
|
|
402
641
|
//#endregion
|
|
403
|
-
export { c as BLIND_SPOTS,
|
|
642
|
+
export { c as BLIND_SPOTS, S as CORE_FLAGS, x as DEVTOOLS_OWNED_FLAGS, C as FLAG_REGISTRY, y as JUDGING_PROTOCOL, e as LONG_GAP_MS, j as MAX_PERSISTED_BYTES, A as MAX_PERSISTED_FLIGHTS, i as MID_FLIGHT_TASK_MS, n as OPENING_WINDOW_LEAD_MS, r as OPENING_WINDOW_TAIL_MS, b as PANEL_HEIGHT_KEY, se as REPORT_SCHEMA_VERSION, w as RETIRED_FLAGS, T as RETIRED_MARKER, a as STALL_MS, t as STUCK_STATUS_MS, k as TRACE_KEY, ue as attachDevtoolsHud, $ as attachDevtoolsPanel, le as attachFlightRecorder, v as captureEnvironment, Y as classifyDriver, P as clearTrace, J as computeFrameStats, q as computePhaseStats, o as deriveFlightAnomalies, O as deriveOverrideWarnings, G as derivePreconditions, s as deriveReportAnomalies, oe as deriveVerdict, f as detectEngine, g as developmentHints, p as isEmulationSuspected, X as kindFromStatus, F as loadTrace, ie as parseTranslateX, m as sampleRafCadence, N as saveTrace, ne as snapshotOverrides, u as summariseBuckets };
|