Files
iptvnator/apps/electron-backend-e2e/src/performance/xtream-phase-event-pairing.ts
T
4gray a2fafcfc08 test(performance): add end-to-end Xtream benchmark harness (#1300)
* docs(performance): plan Xtream benchmark

* feat(xtream-mock-server): add deterministic 100k fixture

* style(xtream-mock-server): apply repository formatting

* fix(xtream-mock-server): harden performance fixture data

* feat(xtream-mock-server): add performance control plane

* docs(performance): correct Xtream capture plan

* fix(xtream-mock-server): harden performance controls

* fix(xtream-mock-server): harden control lifecycle

* feat(performance): add Xtream preload markers

* feat(performance): trace Xtream main phases

* feat(performance): mark Xtream store publications

* feat(performance): trace Xtream database phases

* feat(performance): trace Xtream delete cancellation

* feat(performance): capture Xtream phase attribution

* feat(performance): mark Sources Xtream refresh

* test(performance): define Xtream benchmark evidence contracts

* test(performance): add Xtream benchmark runner

* test(performance): surface failure evidence writes

* test(performance): align database read clock

* test(performance): preserve capture failure contracts
2026-07-28 08:08:07 +02:00

101 lines
3.3 KiB
TypeScript

import {
isExactRecord,
isFiniteNonNegative,
isSafeNonNegativeInteger,
} from './xtream-exact-schema';
import type {
XtreamAttributionPhaseEvent,
XtreamPhaseAttributionInput,
} from './xtream-phase-attribution';
import { fitsPerformanceDurationEnvelope } from './performance-phase-duration-envelope';
import { XTREAM_ATTRIBUTION_PHASE } from './xtream-phase-inventory';
import { semanticTypeFromXtreamPhaseSource } from './xtream-phase-semantic-source';
import type { XtreamTopologyPhaseSpan } from './xtream-phase-topology';
const PHASES = new Set<string>(Object.values(XTREAM_ATTRIBUTION_PHASE));
export function pairXtreamPhaseEvents(
input: XtreamPhaseAttributionInput
): readonly XtreamTopologyPhaseSpan[] {
const groups = new Map<string, XtreamAttributionPhaseEvent[]>();
for (const event of input.events) {
assertCanonicalEvent(event);
const key = `${event.phase}\0${event.correlationId}`;
groups.set(key, [...(groups.get(key) ?? []), event]);
}
return [...groups.values()].map((events) => pairGroup(input, events));
}
function assertCanonicalEvent(event: XtreamAttributionPhaseEvent): void {
if (
!isExactRecord(event, [
'boundary',
'categoryType',
'contentType',
'correlationId',
'durationMs',
'epochMs',
'itemCount',
'phase',
'providerAction',
'semanticType',
]) ||
!PHASES.has(event.phase) ||
!['start', 'end'].includes(event.boundary) ||
typeof event.correlationId !== 'string' ||
event.correlationId.length === 0 ||
semanticTypeFromXtreamPhaseSource(event) !== event.semanticType ||
!isFiniteNonNegative(event.epochMs)
) {
invalid();
}
}
function pairGroup(
input: XtreamPhaseAttributionInput,
events: readonly XtreamAttributionPhaseEvent[]
): XtreamTopologyPhaseSpan {
const [start, end] = events;
if (
events.length !== 2 ||
!start ||
!end ||
start.boundary !== 'start' ||
end.boundary !== 'end' ||
start.durationMs !== null ||
start.itemCount !== null ||
start.providerAction !== end.providerAction ||
start.categoryType !== end.categoryType ||
start.contentType !== end.contentType ||
start.semanticType !== end.semanticType ||
!isFiniteNonNegative(end.durationMs) ||
(end.itemCount !== null && !isSafeNonNegativeInteger(end.itemCount)) ||
start.epochMs < input.operationStartEpochMs ||
end.epochMs < start.epochMs ||
end.epochMs > input.terminalEpochMs ||
!fitsPerformanceDurationEnvelope(
end.durationMs,
input.operationStartEpochMs,
input.terminalEpochMs
)
) {
invalid();
}
return {
categoryType: start.categoryType,
contentType: start.contentType,
correlationId: start.correlationId,
durationMs: end.durationMs,
endEpochMs: end.epochMs,
itemCount: end.itemCount,
phase: start.phase,
providerAction: start.providerAction,
semanticType: start.semanticType,
startEpochMs: start.epochMs,
};
}
function invalid(): never {
throw new Error('invalid Xtream phase event pairing');
}