perf: enforce journey budgets and reference traces

This commit is contained in:
2026-09-02 07:48:02 +03:00
parent 8089d061ec
commit f4cf9fc77e
25 changed files with 1432 additions and 23 deletions

View File

@@ -20,6 +20,9 @@ import type { PortfolioContent, SectionId } from '@/content/types';
import type { SceneHostState } from '@/composables/useSceneController';
import type { MotionPolicy, QualityTier } from '@/journey/motion-policy';
declare const __PORTFOLIO_TEST_BUILD__: boolean;
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
const props = defineProps<{ content: Readonly<PortfolioContent> }>();
const canonicalSectionIds = [
@@ -57,7 +60,13 @@ const adaptive = useAdaptiveQuality({
sceneState,
pageLifecycle,
});
const actualQuality = computed(() => adaptive.snapshot.value.actual);
const requestedPerformanceTier = TEST_BUILD
? new URL(window.location.href).searchParams.get('__portfolio_tier')
: null;
const pinnedPerformanceTier = requestedPerformanceTier === 'high' || requestedPerformanceTier === 'low'
? requestedPerformanceTier
: null;
const actualQuality = computed(() => pinnedPerformanceTier ?? adaptive.snapshot.value.actual);
const activeSectionLabel = computed(() => sectionLabel(journey.value.activeSectionId));
const serverDefaultPolicy: MotionPolicy = {
allowSceneRequest: false,
@@ -70,6 +79,16 @@ const displayedQuality = computed<QualityTier>(() => controlsReady.value ? actua
const displayedSceneState = computed(() => controlsReady.value ? sceneState.value : 'running');
let removePageListeners = (): void => {};
const sampleSceneFrame = (start: number, end: number): void => {
if (pinnedPerformanceTier === null) adaptive.sampleFrame(start, end);
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordSceneFrame(start, end);
};
const updateSceneState = (state: SceneHostState): void => {
sceneState.value = state;
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordSceneState(state);
};
watch(
() => journey.value.activeSectionId,
(id) => navigation.notePassiveSection(id),
@@ -100,6 +119,28 @@ const enableMotion = (): void => {
const resumeMotion = (): void => {
motion.setPaused(false);
adaptive.setMaximum(motion.policy.value.maximumTier, 'manual');
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation('resume');
};
const pauseMotion = (): void => {
motion.setPaused(true);
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation('pause');
};
const startDrive = (): void => {
audio.startFromGesture();
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation('start');
};
const toggleAudioMuted = (): void => {
const action = audio.muted.value ? 'unmute' : 'mute';
audio.toggleMuted();
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation(action);
};
const updateAudioVolume = (value: number): void => {
audio.setVolume(value);
if (TEST_BUILD && value === 0.35) window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation('volume');
};
onMounted(() => {
@@ -126,8 +167,8 @@ onUnmounted(() => removePageListeners());
:policy="motion.policy.value"
:quality="actualQuality"
:scene-description="content.sceneDescription"
:sample-frame="adaptive.sampleFrame"
@state-change="sceneState = $event"
:sample-frame="sampleSceneFrame"
@state-change="updateSceneState"
/>
<JourneyHud
:journey="journey"
@@ -203,13 +244,13 @@ onUnmounted(() => removePageListeners());
:audio-state="audio.state.value"
:audio-muted="audio.muted.value"
:audio-volume="controlsReady ? motion.volume.value : 0.4"
@pause="motion.setPaused(true)"
@pause="pauseMotion"
@resume="resumeMotion"
@enable="enableMotion"
@quality-change="setQuality"
@audio-start="audio.startFromGesture"
@audio-start="startDrive"
@audio-resume="audio.resumeFromGesture"
@audio-mute-toggle="audio.toggleMuted"
@audio-volume-change="audio.setVolume"
@audio-mute-toggle="toggleAudioMuted"
@audio-volume-change="updateAudioVolume"
/>
</template>

View File

@@ -86,9 +86,6 @@ const changeVolume = (event: Event): void => {
type="button"
@click="emit('audioResume')"
>Resume sound</button>
<button type="button" @click="emit('audioMuteToggle')">
{{ audioMuted ? 'Unmute sound' : 'Mute sound' }}
</button>
<label>
<span>Sound volume</span>
<input
@@ -101,6 +98,9 @@ const changeVolume = (event: Event): void => {
@input="changeVolume"
>
</label>
<button type="button" @click="emit('audioMuteToggle')">
{{ audioMuted ? 'Unmute sound' : 'Mute sound' }}
</button>
</div>
<label>
<span>Quality</span>

View File

@@ -7,6 +7,17 @@ const props = defineProps<{
journey: JourneySnapshot;
onSectionLinkClick: (event: MouseEvent) => void;
}>();
const compactLabels: Readonly<Record<SectionId, string>> = {
start: 'Start',
profile: 'Profile',
experience: 'Career',
infrastructure: 'Infra',
'selected-builds': 'Builds',
'additional-work': 'More work',
toolkit: 'Toolkit',
contact: 'Contact',
};
</script>
<template>
@@ -15,11 +26,13 @@ const props = defineProps<{
<li v-for="item in items" :key="item.id">
<a
:href="`#${item.id}`"
:aria-label="item.label"
:data-compact-label="compactLabels[item.id]"
:aria-current="
props.journey.activeSectionId === item.id ? 'page' : undefined
"
@click="props.onSectionLinkClick"
>{{ item.label }}</a
><span class="site-navigation__full-label" aria-hidden="true">{{ item.label }}</span></a
>
</li>
</ul>

View File

@@ -13,6 +13,14 @@ if (requestsTestFault) {
await installAuthorizedTestHooks();
}
const requestsPerformanceTrace = TEST_BUILD
&& new URL(location.href).searchParams.get('__portfolio_performance') === 'drive-trace.v1'
&& new URL(location.href).searchParams.has('__portfolio_test_token');
if (requestsPerformanceTrace) {
const { installAuthorizedPerformanceInstrumentation } = await import('./testing/performance-instrumentation');
await installAuthorizedPerformanceInstrumentation();
}
export const readProductionInputsSnapshot = (source: Document): Readonly<ProductionInputs> => {
const snapshot = source.getElementById('portfolio-inputs');
if (

View File

@@ -1,6 +1,9 @@
import type { SectionId } from "@/content/types";
import type { JourneySource } from "./types";
declare const __PORTFOLIO_TEST_BUILD__: boolean;
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
export interface NavigationState {
epoch: number;
source: JourneySource;
@@ -162,6 +165,10 @@ export function createNavigationController(
source,
destinationId,
};
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.noteNavigationEpoch(currentState.epoch);
if (TEST_BUILD && source === 'explicit-navigation' && (destinationId === 'toolkit' || destinationId === 'contact')) {
window.__PORTFOLIO_PERFORMANCE__?.recordActionMutation(destinationId);
}
emit();
return currentState.epoch;
};
@@ -184,6 +191,7 @@ export function createNavigationController(
) {
return;
}
if (TEST_BUILD && window.__PORTFOLIO_PERFORMANCE__?.holdNavigationSettlement(epoch)) return;
cancelSettle();
frameId = runtime.requestFrame(() => {
frameId = undefined;
@@ -202,6 +210,7 @@ export function createNavigationController(
id: SectionId,
target: HTMLElement,
): void => {
if (TEST_BUILD) window.__PORTFOLIO_PERFORMANCE__?.registerNavigationSettlement(epoch);
settleTimerId = runtime.setTimer(() => {
settleTimerId = undefined;
if (

View File

@@ -6,7 +6,7 @@
display: grid;
gap: var(--space-2);
min-width: 0;
padding: var(--space-4) 4vw var(--space-3);
padding: calc(var(--space-4) + 44px) 4vw var(--space-3);
border-block-end: var(--panel-border);
background: #0b111b;
}
@@ -21,14 +21,20 @@
}
.site-navigation {
margin-block-start: var(--space-1);
position: fixed;
z-index: 3;
inset: 0 0 auto;
min-block-size: 44px;
border-block-end: var(--panel-border);
background: rgb(7 13 23 / 94%);
backdrop-filter: blur(10px);
}
.site-navigation ul {
display: flex;
flex-wrap: wrap;
display: grid;
grid-template-columns: repeat(8, minmax(0, 1fr));
gap: 0.25rem;
max-inline-size: 78rem;
max-inline-size: 90rem;
margin: 0;
padding: 0;
list-style: none;
@@ -38,7 +44,8 @@
display: inline-flex;
align-items: center;
min-block-size: 44px;
padding-inline: 0.7rem;
justify-content: center;
padding-inline: 0.4rem;
color: var(--text-muted);
font-family: var(--mono);
font-size: var(--step--1);
@@ -63,7 +70,7 @@
min-width: 0;
margin: 0 1rem var(--space-4);
padding: var(--space-3);
scroll-margin-block: var(--space-3);
scroll-margin-block-start: calc(44px + var(--space-3));
border: var(--panel-border);
border-radius: 2px;
background: var(--surface);
@@ -89,6 +96,26 @@
}
@media (max-width: 767px) {
.site-header {
padding-block-start: calc(var(--space-4) + 88px);
}
.site-navigation ul {
grid-template-columns: repeat(4, minmax(0, 1fr));
}
.site-navigation__full-label {
display: none;
}
.site-navigation a::after {
content: attr(data-compact-label);
}
.portfolio-section {
scroll-margin-block-start: calc(88px + var(--space-3));
}
.project-link,
.contact-link,
.contact-social-link {

View File

@@ -0,0 +1,394 @@
declare const __PORTFOLIO_TEST_BUILD__: boolean;
declare const __PORTFOLIO_TEST_TOKEN_DIGEST__: string;
const TEST_BUILD = typeof __PORTFOLIO_TEST_BUILD__ !== 'undefined' && __PORTFOLIO_TEST_BUILD__;
const TEST_TOKEN_DIGEST = typeof __PORTFOLIO_TEST_TOKEN_DIGEST__ === 'undefined'
? ''
: __PORTFOLIO_TEST_TOKEN_DIGEST__;
export interface LayoutShiftSample {
startTime: number;
value: number;
hadRecentInput: boolean;
}
export interface LongTaskSample {
startTime: number;
duration: number;
}
export interface EventTimingSample {
target: string;
startTime: number;
duration: number;
interactionId: number;
}
export interface ScriptedActionSample {
id: string;
target: string;
dispatchTime: number;
acknowledgementCount: number;
mutationTime: number | null;
doubleRafTime: number | null;
eventTimingSupported: boolean;
eventEntries: readonly EventTimingSample[];
}
export interface SceneInterval { start: number; end: number }
export interface SceneFrameSample { start: number; end: number }
export const nearestRankP95 = (samples: readonly number[]): number => {
if (samples.length === 0) throw new Error('At least one sample is required.');
const sorted = [...samples].sort((left, right) => left - right);
return sorted[Math.ceil(0.95 * sorted.length) - 1]!;
};
export const latestLcpBeforeCutoff = (entries: readonly number[], cutoff: number): number => {
const eligible = entries.filter((entry) => entry < cutoff);
if (eligible.length === 0) throw new Error('An LCP entry is required before the cutoff.');
return Math.max(...eligible);
};
export const calculateCls = (entries: readonly LayoutShiftSample[]): number => {
const eligible = entries
.filter((entry) => !entry.hadRecentInput)
.sort((left, right) => left.startTime - right.startTime);
let maximum = 0;
let windowStart = -Infinity;
let previous = -Infinity;
let sum = 0;
for (const entry of eligible) {
if (entry.startTime - previous > 1_000 || entry.startTime - windowStart > 5_000) {
windowStart = entry.startTime;
sum = 0;
}
sum += entry.value;
previous = entry.startTime;
maximum = Math.max(maximum, sum);
}
return maximum;
};
export const calculateLabTbt = (
tasks: readonly LongTaskSample[],
fcp: number | null,
runningAt: number,
): number => {
if (fcp === null) throw new Error('FCP is required for lab total blocking time.');
return tasks.reduce((total, task) => {
const start = Math.max(task.startTime + 50, fcp);
const end = Math.min(task.startTime + task.duration, runningAt);
return total + Math.max(0, end - start);
}, 0);
};
export const postRunningLongTasks = (
tasks: readonly LongTaskSample[],
runningAt: number,
traceEnd: number,
): LongTaskSample[] => tasks.filter((task) => (
task.startTime < traceEnd && task.startTime + task.duration > runningAt
));
const exactActionIds = new Set(['start', 'volume', 'mute', 'unmute', 'pause', 'resume', 'toolkit', 'contact']);
export const evaluateEventToNextPaint = (
actions: readonly ScriptedActionSample[],
): { values: number[]; p95: number } => {
if (actions.length !== 8 || new Set(actions.map((action) => action.id)).size !== 8 || actions.some((action) => !exactActionIds.has(action.id))) {
throw new Error('The exact eight scripted actions are required.');
}
const values = actions.map((action) => {
if (action.acknowledgementCount !== 1) throw new Error('Each action requires exactly one acknowledgement.');
if (action.mutationTime === null || action.mutationTime > action.dispatchTime + 500) throw new Error('The exact state mutation missed its deadline.');
if (action.doubleRafTime === null || action.doubleRafTime > action.dispatchTime + 500) throw new Error('Double RAF confirmation missed its deadline.');
if (!action.eventTimingSupported) throw new Error('Event Timing observation is unsupported.');
const matching = action.eventEntries.filter((entry) => (
entry.target === action.target
&& entry.startTime >= action.dispatchTime
&& entry.startTime <= action.dispatchTime + 500
));
if (matching.length === 0) return 16;
const groups = new Map<number, number>();
for (const entry of matching) {
if (entry.interactionId === 0) continue;
groups.set(entry.interactionId, Math.max(groups.get(entry.interactionId) ?? 0, entry.duration));
}
if (groups.size !== 1) throw new Error('Event Timing groups are ambiguous.');
return [...groups.values()][0]!;
});
return { values, p95: nearestRankP95(values) };
};
export const evaluateSceneContinuity = (
intervals: readonly SceneInterval[],
callbacks: readonly SceneFrameSample[],
expectedFramePeriod: number,
): { passes: boolean; expectedCallbacks: number; actualCallbacks: number } => {
if (!(expectedFramePeriod > 0)) throw new Error('Expected frame period must be positive.');
const eligible = intervals.filter((interval) => interval.end - interval.start >= expectedFramePeriod);
let expectedCallbacks = 0;
let actualCallbacks = 0;
let boundariesPass = eligible.length > 0;
for (const interval of eligible) {
expectedCallbacks += Math.floor((interval.end - interval.start) / expectedFramePeriod);
const inside = callbacks.filter((sample) => sample.start >= interval.start && sample.end <= interval.end);
actualCallbacks += inside.length;
if (inside.length === 0) {
boundariesPass = false;
continue;
}
if (inside[0]!.start - interval.start > 3 * expectedFramePeriod) boundariesPass = false;
for (let index = 1; index < inside.length; index += 1) {
if (inside[index]!.start - inside[index - 1]!.start > 3 * expectedFramePeriod) boundariesPass = false;
}
if (interval.end - inside.at(-1)!.end > 3 * expectedFramePeriod) boundariesPass = false;
}
const coverage = expectedCallbacks > 0 ? actualCallbacks / expectedCallbacks : 0;
return { passes: boundariesPass && coverage >= 0.9, expectedCallbacks, actualCallbacks };
};
export const calculateLostPresentationShare = (
rafTimestamps: readonly number[],
expectedFramePeriod: number,
minimumOpportunities: number,
): { opportunities: number; lost: number; share: number; hasSufficientCoverage: boolean } => {
let opportunities = 0;
let lost = 0;
for (let index = 1; index < rafTimestamps.length; index += 1) {
const interval = rafTimestamps[index]! - rafTimestamps[index - 1]!;
const nextOpportunities = Math.max(1, Math.round(interval / expectedFramePeriod));
opportunities += nextOpportunities;
lost += nextOpportunities - 1;
}
return {
opportunities,
lost,
share: opportunities === 0 ? 1 : lost / opportunities,
hasSufficientCoverage: opportunities >= minimumOpportunities,
};
};
export const unexpectedLateShifts = (
entries: readonly LayoutShiftSample[],
firstSceneFrame: number,
traceEnd: number,
): LayoutShiftSample[] => entries.filter((entry) => (
!entry.hadRecentInput && entry.startTime >= firstSceneFrame && entry.startTime < traceEnd
));
interface PerformanceSnapshot {
version: 'drive-trace.v1';
lcp: readonly number[];
layoutShifts: readonly LayoutShiftSample[];
longTasks: readonly LongTaskSample[];
pageRafs: readonly number[];
sceneFrames: readonly SceneFrameSample[];
sceneIntervals: readonly SceneInterval[];
firstSceneFrame: number | null;
traceStart: number | null;
traceEnd: number | null;
cutoff: number;
navigationBarrier: { armed: boolean; pendingEpoch: number | null; cancelledEpoch: number | null };
actions: readonly ScriptedActionSample[];
}
interface PerformanceHooks {
readonly version: 'drive-trace.v1';
startTrace(): void;
endTrace(): void;
recordSceneFrame(start: number, end: number): void;
recordSceneState(state: string): void;
armNavigationSettlementBarrier(): void;
registerNavigationSettlement(epoch: number): void;
holdNavigationSettlement(epoch: number): boolean;
noteNavigationEpoch(epoch: number): void;
beginAction(id: string, selector: string): void;
recordActionMutation(id: string): void;
snapshot(): PerformanceSnapshot;
}
declare global {
interface Window {
__PORTFOLIO_PERFORMANCE__?: PerformanceHooks;
}
}
const digest = async (value: string): Promise<string> => {
const output = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(value));
return [...new Uint8Array(output)].map((byte) => byte.toString(16).padStart(2, '0')).join('');
};
export const installAuthorizedPerformanceInstrumentation = async (): Promise<void> => {
if (!TEST_BUILD) return;
const url = new URL(location.href);
if (url.searchParams.get('__portfolio_performance') !== 'drive-trace.v1') return;
const token = url.searchParams.get('__portfolio_test_token');
if (token === null || await digest(token) !== TEST_TOKEN_DIGEST) return;
const lcp: number[] = [];
const layoutShifts: LayoutShiftSample[] = [];
const longTasks: LongTaskSample[] = [];
const pageRafs: number[] = [];
const sceneFrames: SceneFrameSample[] = [];
const sceneIntervals: SceneInterval[] = [];
let firstSceneFrame: number | null = null;
let traceStart: number | null = null;
let traceEnd: number | null = null;
let runningIntervalStart: number | null = null;
let cutoff = Infinity;
let sentinel = 0;
let barrierArmed = false;
let barrierPendingEpoch: number | null = null;
let barrierCancelledEpoch: number | null = null;
const actionRecords = new Map<string, ScriptedActionSample & { element: Element | null }>();
const observe = (type: string, callback: (entry: PerformanceEntry) => void): void => {
if (typeof PerformanceObserver === 'undefined') return;
try {
const observer = new PerformanceObserver((list) => list.getEntries().forEach(callback));
observer.observe({ type, buffered: true });
} catch { /* unsupported entry type */ }
};
observe('largest-contentful-paint', (entry) => lcp.push(entry.startTime));
observe('layout-shift', (entry) => {
const shift = entry as PerformanceEntry & { value?: number; hadRecentInput?: boolean };
layoutShifts.push({ startTime: shift.startTime, value: shift.value ?? 0, hadRecentInput: shift.hadRecentInput ?? false });
});
observe('longtask', (entry) => longTasks.push({ startTime: entry.startTime, duration: entry.duration }));
let eventTimingSupported = false;
if (typeof PerformanceObserver !== 'undefined') {
try {
const eventObserver = new PerformanceObserver((list) => {
for (const entry of list.getEntries()) {
const timed = entry as PerformanceEntry & { interactionId?: number; target?: Node | null };
for (const record of actionRecords.values()) {
if (timed.target === record.element) {
(record.eventEntries as EventTimingSample[]).push({
target: record.id,
startTime: timed.startTime,
duration: timed.duration,
interactionId: timed.interactionId ?? 0,
});
}
}
}
});
const eventOptions = { type: 'event', buffered: true, durationThreshold: 16 } as PerformanceObserverInit & { durationThreshold: number };
eventObserver.observe(eventOptions);
eventTimingSupported = true;
} catch { /* Event Timing unsupported */ }
}
const cutOff = (event: Event): void => {
if (event.isTrusted) cutoff = Math.min(cutoff, performance.now());
};
addEventListener('pointerdown', cutOff, { capture: true, once: true });
addEventListener('keydown', cutOff, { capture: true, once: true });
document.addEventListener('visibilitychange', () => {
if (document.hidden) cutoff = Math.min(cutoff, performance.now());
});
const sentinelFrame = (now: number): void => {
if (traceStart !== null && traceEnd === null) pageRafs.push(now);
sentinel = requestAnimationFrame(sentinelFrame);
};
sentinel = requestAnimationFrame(sentinelFrame);
const hooks: PerformanceHooks = {
version: 'drive-trace.v1',
startTrace() {
traceStart = performance.now();
traceEnd = null;
pageRafs.length = 0;
sceneFrames.length = 0;
sceneIntervals.length = 0;
runningIntervalStart = document.querySelector('.journey-world')?.getAttribute('data-scene-state') === 'running' ? traceStart : null;
},
endTrace() {
traceEnd = performance.now();
if (runningIntervalStart !== null) {
sceneIntervals.push({ start: runningIntervalStart, end: traceEnd });
runningIntervalStart = null;
}
cancelAnimationFrame(sentinel);
},
recordSceneFrame(start, end) {
if (firstSceneFrame === null) firstSceneFrame = end;
if (traceStart !== null && traceEnd === null) sceneFrames.push({ start, end });
},
recordSceneState(state) {
const now = performance.now();
if (traceStart === null || traceEnd !== null) return;
if (state === 'running' && runningIntervalStart === null) runningIntervalStart = now;
if (state !== 'running' && runningIntervalStart !== null) {
sceneIntervals.push({ start: runningIntervalStart, end: now });
runningIntervalStart = null;
}
},
armNavigationSettlementBarrier() {
barrierArmed = true;
barrierPendingEpoch = null;
barrierCancelledEpoch = null;
},
registerNavigationSettlement(epoch) {
if (barrierArmed) barrierPendingEpoch = epoch;
},
holdNavigationSettlement(epoch) {
return barrierArmed && barrierPendingEpoch === epoch;
},
noteNavigationEpoch(epoch) {
if (barrierArmed && barrierPendingEpoch !== null && barrierPendingEpoch !== epoch) {
barrierCancelledEpoch = barrierPendingEpoch;
barrierPendingEpoch = null;
barrierArmed = false;
}
},
beginAction(id, selector) {
if (!exactActionIds.has(id) || actionRecords.has(id)) throw new Error('The performance action is invalid or duplicated.');
const element = document.querySelector(selector);
if (!(element instanceof Element)) throw new Error('The performance action target is unavailable.');
actionRecords.set(id, {
id,
target: id,
dispatchTime: performance.now(),
acknowledgementCount: 0,
mutationTime: null,
doubleRafTime: null,
eventTimingSupported,
eventEntries: [],
element,
});
},
recordActionMutation(id) {
const record = actionRecords.get(id);
if (record === undefined) return;
record.acknowledgementCount += 1;
record.mutationTime = performance.now();
requestAnimationFrame(() => requestAnimationFrame(() => { record.doubleRafTime = performance.now(); }));
},
snapshot: () => Object.freeze({
version: 'drive-trace.v1' as const,
lcp: Object.freeze([...lcp]),
layoutShifts: Object.freeze([...layoutShifts]),
longTasks: Object.freeze([...longTasks]),
pageRafs: Object.freeze([...pageRafs]),
sceneFrames: Object.freeze([...sceneFrames]),
sceneIntervals: Object.freeze([...sceneIntervals]),
firstSceneFrame,
traceStart,
traceEnd,
cutoff,
navigationBarrier: Object.freeze({ armed: barrierArmed, pendingEpoch: barrierPendingEpoch, cancelledEpoch: barrierCancelledEpoch }),
actions: Object.freeze([...actionRecords.values()].map(({ element: _element, ...record }) => Object.freeze({
...record,
eventEntries: Object.freeze([...record.eventEntries]),
}))),
}),
};
Object.defineProperty(window, '__PORTFOLIO_PERFORMANCE__', {
configurable: false,
enumerable: false,
writable: false,
value: Object.freeze(hooks),
});
};