@deeeed/metamask-harness 0.43.0 → 0.44.1

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.
@@ -1,4 +1,5 @@
1
- import { mkdir, readFile, rm, stat, writeFile } from "node:fs/promises";
1
+ import { createHash } from "node:crypto";
2
+ import { mkdir, open, readFile, rm, stat, writeFile } from "node:fs/promises";
2
3
  import path from "node:path";
3
4
 
4
5
  const MARKER = "[PerpsPerf]";
@@ -7,12 +8,39 @@ const DETAILED_MARKERS = [MARKER, LEGACY_MARKER];
7
8
  const STARTUP_MARKER = "[StartupPerf]";
8
9
  const LOAD_PROOF_MARKER = "[PerpsLoadProof]";
9
10
  const STATE_FILE = ".homepage-performance-capture.json";
11
+ const CAPTURE_BOUNDARY_BYTES = 4096;
12
+ const BOOTSTRAP_LOOKBACK_BYTES = 512 * 1024;
10
13
  const FRESH_SOURCES = new Set([
11
14
  "fresh_socket",
12
15
  "provider_snapshot",
13
16
  "terminal_global_snapshot_v2",
17
+ "terminal_v2",
14
18
  "provider",
15
19
  ]);
20
+ const SURFACE_STAGE_ORDER = [
21
+ "surface_demand",
22
+ "surface_initial_ui_recorded",
23
+ "surface_resolved_recorded",
24
+ "surface_live_recorded",
25
+ ];
26
+ const SURFACE_STAGES = new Set(SURFACE_STAGE_ORDER);
27
+ const PERFORMANCE_IDENTITY_FIELDS = [
28
+ "demand_id",
29
+ "perps_session_id",
30
+ "lifecycle",
31
+ "account_generation",
32
+ "context_generation",
33
+ ];
34
+ const LOAD_PROOF_BASE_IDENTITY_FIELDS = PERFORMANCE_IDENTITY_FIELDS.slice(1);
35
+ const LOAD_PROOF_IDENTITY_FIELDS = [
36
+ ...LOAD_PROOF_BASE_IDENTITY_FIELDS,
37
+ "connection_generation",
38
+ ];
39
+ const GENERATION_IDENTITY_FIELDS = new Set([
40
+ "account_generation",
41
+ "context_generation",
42
+ "connection_generation",
43
+ ]);
16
44
 
17
45
  function resolveWithin(root, relativePath, label) {
18
46
  const absoluteRoot = path.resolve(root);
@@ -24,15 +52,83 @@ function resolveWithin(root, relativePath, label) {
24
52
  return absolutePath;
25
53
  }
26
54
 
27
- async function fileSize(file) {
55
+ async function fileState(file) {
28
56
  try {
29
- return (await stat(file)).size;
57
+ const value = await stat(file);
58
+ return { size: value.size, device: value.dev, inode: value.ino };
30
59
  } catch (error) {
31
- if (error?.code === "ENOENT") return 0;
60
+ if (error?.code === "ENOENT") return null;
32
61
  throw error;
33
62
  }
34
63
  }
35
64
 
65
+ async function readFileRange(file, start, length) {
66
+ if (length === 0) return Buffer.alloc(0);
67
+ const handle = await open(file, "r");
68
+ try {
69
+ const buffer = Buffer.alloc(length);
70
+ const { bytesRead } = await handle.read(buffer, 0, length, start);
71
+ return buffer.subarray(0, bytesRead);
72
+ } finally {
73
+ await handle.close();
74
+ }
75
+ }
76
+
77
+ function captureBoundary(content, offset) {
78
+ const start = Math.max(0, offset - CAPTURE_BOUNDARY_BYTES);
79
+ const bytes = content.subarray(start, offset);
80
+ return {
81
+ start,
82
+ length: bytes.length,
83
+ sha256: createHash("sha256").update(bytes).digest("hex"),
84
+ };
85
+ }
86
+
87
+ function captureBoundaryBytes(start, bytes) {
88
+ return {
89
+ start,
90
+ length: bytes.length,
91
+ sha256: createHash("sha256").update(bytes).digest("hex"),
92
+ };
93
+ }
94
+
95
+ async function readCaptureSource(sourceFile, state) {
96
+ const current = await fileState(sourceFile);
97
+ if (!current) {
98
+ if (state.offset === 0 && state.sourceIdentity === null) {
99
+ return Buffer.alloc(0);
100
+ }
101
+ throw new Error("Perps performance capture source disappeared after phase=start.");
102
+ }
103
+ if (state.sourceIdentity === null) {
104
+ state.sourceIdentity = current;
105
+ }
106
+ if (
107
+ state.sourceIdentity &&
108
+ (current.device !== state.sourceIdentity.device ||
109
+ current.inode !== state.sourceIdentity.inode)
110
+ ) {
111
+ throw new Error("Perps performance capture source was replaced after phase=start.");
112
+ }
113
+ if (current.size < state.offset) {
114
+ throw new Error("Perps performance capture source shrank after phase=start.");
115
+ }
116
+ const content = await readFile(sourceFile);
117
+ const boundary = captureBoundary(content, state.offset);
118
+ if (state.sourceBoundary === null) {
119
+ state.sourceBoundary = boundary;
120
+ } else if (
121
+ boundary.start !== state.sourceBoundary.start ||
122
+ boundary.length !== state.sourceBoundary.length ||
123
+ boundary.sha256 !== state.sourceBoundary.sha256
124
+ ) {
125
+ throw new Error(
126
+ "Perps performance capture source was truncated or rewritten after phase=start.",
127
+ );
128
+ }
129
+ return content;
130
+ }
131
+
36
132
  function parseRecord(line, marker) {
37
133
  const markerIndex = line.indexOf(marker);
38
134
  if (markerIndex < 0) return null;
@@ -56,83 +152,279 @@ function parseDetailedRecord(line) {
56
152
  return marker ? parseRecord(line, marker) : null;
57
153
  }
58
154
 
59
- function latestPerpsBootstrapStartRecord(content) {
60
- return content
61
- .split(/\r?\n/u)
62
- .filter((line) => line.includes(LOAD_PROOF_MARKER))
63
- .map((line) => parseRecord(line, LOAD_PROOF_MARKER))
64
- .filter((record) => record?.stage === "perps_bootstrap_start")
65
- .at(-1) ?? null;
155
+ function identityField(record, field) {
156
+ if (field === "perps_session_id") {
157
+ if (Object.hasOwn(record, "perps_session_id")) {
158
+ return { present: true, value: record.perps_session_id };
159
+ }
160
+ if (Object.hasOwn(record, "session_id")) {
161
+ return { present: true, value: record.session_id };
162
+ }
163
+ return { present: false, value: undefined };
164
+ }
165
+ return Object.hasOwn(record, field)
166
+ ? { present: true, value: record[field] }
167
+ : { present: false, value: undefined };
168
+ }
169
+
170
+ function hasValidIdentityField(record, field) {
171
+ const identity = identityField(record, field);
172
+ if (
173
+ !identity.present ||
174
+ identity.value === null ||
175
+ identity.value === undefined
176
+ ) {
177
+ return false;
178
+ }
179
+ if (GENERATION_IDENTITY_FIELDS.has(field)) {
180
+ return (
181
+ typeof identity.value === "number" &&
182
+ Number.isInteger(identity.value) &&
183
+ identity.value >= 0
184
+ );
185
+ }
186
+ return String(identity.value).trim().length > 0;
187
+ }
188
+
189
+ function hasCompleteIdentity(record, fields = PERFORMANCE_IDENTITY_FIELDS) {
190
+ return fields.every((field) => hasValidIdentityField(record, field));
66
191
  }
67
192
 
68
- function consoleClockMs(line) {
69
- const match = line.match(/\b(\d{2}):(\d{2}):(\d{2})\.(\d{3})\b/u);
70
- if (!match) return null;
193
+ function sameIdentity(left, right, fields = PERFORMANCE_IDENTITY_FIELDS) {
71
194
  return (
72
- Number(match[1]) * 3_600_000 +
73
- Number(match[2]) * 60_000 +
74
- Number(match[3]) * 1_000 +
75
- Number(match[4])
195
+ hasCompleteIdentity(left, fields) &&
196
+ hasCompleteIdentity(right, fields) &&
197
+ fields.every((field) => {
198
+ const leftField = identityField(left, field);
199
+ const rightField = identityField(right, field);
200
+ return String(leftField.value) === String(rightField.value);
201
+ })
76
202
  );
77
203
  }
78
204
 
79
- function existingLiveStreamRecords(segmentLines, markerRecords) {
80
- let bootstrapLineIndex = -1;
81
- segmentLines.forEach((line, index) => {
205
+ function identityKey(record, fields = PERFORMANCE_IDENTITY_FIELDS) {
206
+ return JSON.stringify(
207
+ fields.map((field) => {
208
+ const value = identityField(record, field);
209
+ return value.present ? [field, String(value.value)] : [field, "<missing>"];
210
+ }),
211
+ );
212
+ }
213
+
214
+ function performanceRecordTime(record) {
215
+ const value = Number(
216
+ record.frame_checkpoint_monotonic_ms ?? record.monotonic_ms,
217
+ );
218
+ return Number.isFinite(value) ? value : null;
219
+ }
220
+
221
+ function isAccountContentVariant(value) {
222
+ return ["positions", "orders", "positions_and_orders"].includes(
223
+ String(value ?? ""),
224
+ );
225
+ }
226
+
227
+ function orderedSurfaceSequence(records, demand, requiredStages) {
228
+ const stages = SURFACE_STAGE_ORDER.filter((stage) =>
229
+ requiredStages.includes(stage),
230
+ );
231
+ if (stages.length === 0) return [demand];
232
+ const demandAt = performanceRecordTime(demand);
233
+ if (demandAt === null) return null;
234
+ const sequence = [];
235
+ let previousAt = demandAt;
236
+ for (const stage of stages) {
237
+ if (stage === "surface_demand") {
238
+ sequence.push(demand);
239
+ continue;
240
+ }
241
+ const matches = records
242
+ .filter(
243
+ (record) =>
244
+ record.stage === stage &&
245
+ sameIdentity(record, demand),
246
+ )
247
+ .sort(
248
+ (left, right) =>
249
+ performanceRecordTime(left) - performanceRecordTime(right),
250
+ );
251
+ if (matches.length !== 1) return null;
252
+ const match = matches[0];
253
+ const matchAt = performanceRecordTime(match);
82
254
  if (
83
- line.includes(LOAD_PROOF_MARKER) &&
84
- line.includes('"stage":"perps_bootstrap_start"')
255
+ matchAt === null ||
256
+ matchAt < previousAt ||
257
+ !Number.isFinite(Number(match.duration_ms)) ||
258
+ Number(match.duration_ms) < 0 ||
259
+ (stage === "surface_live_recorded" &&
260
+ (match.fresh_for_lifecycle !== true || !frameIsFresh(match)))
85
261
  ) {
86
- bootstrapLineIndex = index;
262
+ return null;
87
263
  }
88
- });
89
- const bootstrapLine =
90
- bootstrapLineIndex >= 0 ? segmentLines[bootstrapLineIndex] : undefined;
91
- const liveLines =
92
- bootstrapLineIndex >= 0
93
- ? segmentLines.slice(bootstrapLineIndex + 1)
94
- : segmentLines;
95
- const bootstrapClock = bootstrapLine ? consoleClockMs(bootstrapLine) : null;
96
- const bootstrapRecord = markerRecords
97
- .filter((record) => record.stage === "perps_bootstrap_start")
98
- .at(-1);
99
- const patterns = new Map([
100
- ["PerpsWS: First price data received", "prices"],
101
- ["PerpsWS: First position data received", "positions"],
102
- ["PerpsWS: First order data received", "orders"],
103
- ["PerpsWS: First account data received", "account"],
104
- ]);
105
- const records = [];
106
- for (const [message, stream] of patterns) {
107
- const line = liveLines.find((candidate) => candidate.includes(message));
108
- if (!line) continue;
109
- const eventClock = consoleClockMs(line);
110
- let elapsedMs = null;
111
- if (bootstrapClock !== null && eventClock !== null) {
112
- elapsedMs = eventClock - bootstrapClock;
113
- if (elapsedMs < 0) elapsedMs += 24 * 3_600_000;
264
+ sequence.push(match);
265
+ previousAt = matchAt;
266
+ }
267
+ return sequence;
268
+ }
269
+
270
+ function coherentPerformanceProof(
271
+ records,
272
+ loadProofRecords,
273
+ requiredStages,
274
+ requiredLiveStreams,
275
+ expectedLifecycle = null,
276
+ expectedContentVariant = null,
277
+ ) {
278
+ const requiredSurfaceStages = requiredStages.filter((stage) =>
279
+ SURFACE_STAGES.has(stage),
280
+ );
281
+ const required =
282
+ requiredSurfaceStages.length > 0 || requiredLiveStreams.length > 0;
283
+ if (!required) {
284
+ return {
285
+ status: "not_required",
286
+ demand: null,
287
+ identity: null,
288
+ missingLiveStreams: [],
289
+ sequence: [],
290
+ };
291
+ }
292
+ const demands = records.filter((record) => record.stage === "surface_demand");
293
+ let best = null;
294
+ for (const demand of demands) {
295
+ if (!hasCompleteIdentity(demand)) continue;
296
+ if (
297
+ records.filter(
298
+ (record) =>
299
+ record.stage === "surface_demand" && sameIdentity(record, demand),
300
+ ).length !== 1
301
+ ) {
302
+ continue;
114
303
  }
115
- records.push({
116
- stage: "values_ready",
117
- stream,
118
- source: "fresh_socket",
119
- item_count: null,
120
- elapsed_ms: elapsedMs,
121
- monotonic_ms:
122
- elapsedMs !== null &&
123
- Number.isFinite(Number(bootstrapRecord?.monotonic_ms))
124
- ? Number(bootstrapRecord.monotonic_ms) + elapsedMs
125
- : null,
126
- evidence: "existing_sentry_ws_marker",
127
- });
304
+ if (
305
+ expectedLifecycle !== null &&
306
+ String(demand.lifecycle ?? "") !== expectedLifecycle
307
+ ) {
308
+ continue;
309
+ }
310
+ const sequence = orderedSurfaceSequence(
311
+ records,
312
+ demand,
313
+ requiredSurfaceStages,
314
+ );
315
+ if (!sequence) continue;
316
+ if (
317
+ expectedContentVariant !== null &&
318
+ sequence
319
+ .filter((record) => record.stage !== "surface_demand")
320
+ .some(
321
+ (record) =>
322
+ !contentVariantSatisfies(
323
+ String(record.content_variant ?? ""),
324
+ expectedContentVariant,
325
+ ),
326
+ )
327
+ ) {
328
+ continue;
329
+ }
330
+ const liveRecords = loadProofRecords.filter(
331
+ (record) =>
332
+ record.stage === "values_ready" &&
333
+ record.source === "fresh_socket" &&
334
+ hasCompleteIdentity(record, LOAD_PROOF_IDENTITY_FIELDS) &&
335
+ sameIdentity(record, demand, LOAD_PROOF_BASE_IDENTITY_FIELDS),
336
+ );
337
+ const connectionGenerations = new Set(
338
+ liveRecords.map((record) => record.connection_generation),
339
+ );
340
+ const liveRecordConnectionGeneration =
341
+ connectionGenerations.size === 1
342
+ ? [...connectionGenerations][0]
343
+ : null;
344
+ const liveSurface = sequence.find(
345
+ (record) => record.stage === "surface_live_recorded",
346
+ );
347
+ const accountLiveSurface =
348
+ liveSurface && isAccountContentVariant(liveSurface.content_variant)
349
+ ? liveSurface
350
+ : null;
351
+ const surfaceConnectionGeneration =
352
+ accountLiveSurface &&
353
+ hasValidIdentityField(accountLiveSurface, "connection_generation")
354
+ ? accountLiveSurface.connection_generation
355
+ : null;
356
+ const identityCoherent =
357
+ connectionGenerations.size <= 1 &&
358
+ (!accountLiveSurface ||
359
+ (surfaceConnectionGeneration !== null &&
360
+ (liveRecordConnectionGeneration === null ||
361
+ surfaceConnectionGeneration === liveRecordConnectionGeneration)));
362
+ const coherentConnectionGeneration =
363
+ liveRecordConnectionGeneration ?? surfaceConnectionGeneration;
364
+ const liveStreams = new Set(
365
+ liveRecordConnectionGeneration === null
366
+ ? []
367
+ : liveRecords.map((record) => String(record.stream ?? "")),
368
+ );
369
+ const missingLiveStreams = requiredLiveStreams.filter(
370
+ (stream) => !liveStreams.has(stream),
371
+ );
372
+ const candidate = {
373
+ demand,
374
+ sequence,
375
+ missingLiveStreams,
376
+ identityCoherent,
377
+ connectionGeneration: coherentConnectionGeneration,
378
+ };
379
+ if (
380
+ !best ||
381
+ Number(identityCoherent) > Number(best.identityCoherent) ||
382
+ (identityCoherent === best.identityCoherent &&
383
+ missingLiveStreams.length < best.missingLiveStreams.length)
384
+ ) {
385
+ best = candidate;
386
+ }
387
+ if (identityCoherent && missingLiveStreams.length === 0) break;
128
388
  }
129
- return records;
389
+ return {
390
+ status:
391
+ best?.identityCoherent && best.missingLiveStreams.length === 0
392
+ ? "pass"
393
+ : "fail",
394
+ demand: best?.demand ?? null,
395
+ identity: best
396
+ ? {
397
+ ...Object.fromEntries(
398
+ PERFORMANCE_IDENTITY_FIELDS.map((field) => {
399
+ const value = identityField(best.demand, field);
400
+ return [field, value.present ? value.value : null];
401
+ }),
402
+ ),
403
+ connection_generation: best.connectionGeneration,
404
+ }
405
+ : null,
406
+ missingLiveStreams: best?.missingLiveStreams ?? requiredLiveStreams,
407
+ sequence: best?.sequence.map((record) => record.stage) ?? [],
408
+ };
409
+ }
410
+
411
+ function latestPerpsBootstrapStartRecord(content) {
412
+ return content
413
+ .split(/\r?\n/u)
414
+ .filter((line) => line.includes(LOAD_PROOF_MARKER))
415
+ .map((line) => parseRecord(line, LOAD_PROOF_MARKER))
416
+ .filter((record) => record?.stage === "perps_bootstrap_start")
417
+ .at(-1) ?? null;
130
418
  }
131
419
 
132
420
  function mergeLoadProofRecords(records) {
133
421
  const byStageStreamSource = new Map();
134
422
  for (const record of records) {
135
- const key = `${record.stage ?? "unknown"}:${record.stream ?? ""}:${record.source ?? ""}`;
423
+ const identityFields =
424
+ record.stage === "values_ready"
425
+ ? LOAD_PROOF_IDENTITY_FIELDS
426
+ : LOAD_PROOF_BASE_IDENTITY_FIELDS;
427
+ const key = `${record.stage ?? "unknown"}:${record.stream ?? ""}:${record.source ?? ""}:${identityKey(record, identityFields)}`;
136
428
  const current = byStageStreamSource.get(key);
137
429
  if (record.stage === "perps_bootstrap_start") {
138
430
  if (
@@ -143,14 +435,9 @@ function mergeLoadProofRecords(records) {
143
435
  }
144
436
  continue;
145
437
  }
146
- const recordIsFallback =
147
- record.evidence === "existing_sentry_ws_marker";
148
- const currentIsFallback =
149
- current?.evidence === "existing_sentry_ws_marker";
150
438
  const recordElapsedMs = Number(record.elapsed_ms);
151
439
  const currentElapsedMs = Number(current?.elapsed_ms);
152
- const sameEvidenceClassEarlier =
153
- recordIsFallback === currentIsFallback &&
440
+ const earlier =
154
441
  record.elapsed_ms !== null &&
155
442
  record.elapsed_ms !== undefined &&
156
443
  Number.isFinite(recordElapsedMs) &&
@@ -158,18 +445,14 @@ function mergeLoadProofRecords(records) {
158
445
  current?.elapsed_ms !== undefined &&
159
446
  Number.isFinite(currentElapsedMs) &&
160
447
  recordElapsedMs < currentElapsedMs;
161
- if (
162
- !current ||
163
- (currentIsFallback && !recordIsFallback) ||
164
- sameEvidenceClassEarlier
165
- ) {
448
+ if (!current || earlier) {
166
449
  byStageStreamSource.set(key, record);
167
450
  }
168
451
  }
169
452
  return [...byStageStreamSource.values()];
170
453
  }
171
454
 
172
- async function waitForPerformanceRecord({ node, sourceFile, offset }) {
455
+ async function waitForPerformanceRecord({ node, sourceFile, state }) {
173
456
  const stage = node.wait_for_stage;
174
457
  const requiredLiveStreams = Array.isArray(node.required_live_streams)
175
458
  ? node.required_live_streams.map(String)
@@ -187,6 +470,9 @@ async function waitForPerformanceRecord({ node, sourceFile, offset }) {
187
470
  ...(node.wait_for_lifecycle !== undefined
188
471
  ? { lifecycle: String(node.wait_for_lifecycle) }
189
472
  : {}),
473
+ ...(node.wait_for_content_variant !== undefined
474
+ ? { content_variant: String(node.wait_for_content_variant) }
475
+ : {}),
190
476
  };
191
477
  const timeoutMs = Math.max(1, Number(node.wait_timeout_ms ?? 60_000));
192
478
  const pollIntervalMs = Math.max(
@@ -196,8 +482,8 @@ async function waitForPerformanceRecord({ node, sourceFile, offset }) {
196
482
  const deadline = Date.now() + timeoutMs;
197
483
 
198
484
  while (true) {
199
- const content = await readFile(sourceFile);
200
- const start = offset <= content.length ? offset : 0;
485
+ const content = await readCaptureSource(sourceFile, state);
486
+ const start = state.offset;
201
487
  const segmentLines = content
202
488
  .subarray(start)
203
489
  .toString("utf8")
@@ -206,33 +492,42 @@ async function waitForPerformanceRecord({ node, sourceFile, offset }) {
206
492
  .filter(detailedMarker)
207
493
  .map(parseDetailedRecord)
208
494
  .filter(Boolean);
209
- const stageMatched =
210
- expected === null ||
211
- performanceRecords.some((record) =>
212
- Object.entries(expected).every(
213
- ([key, value]) => String(record[key] ?? "") === value,
214
- ),
215
- );
216
495
  const markerLoadProofRecords = segmentLines
217
496
  .filter((line) => line.includes(LOAD_PROOF_MARKER))
218
497
  .map((line) => parseRecord(line, LOAD_PROOF_MARKER))
219
498
  .filter(Boolean);
220
- const liveStreams = new Set(
221
- mergeLoadProofRecords([
222
- ...markerLoadProofRecords,
223
- ...existingLiveStreamRecords(segmentLines, markerLoadProofRecords),
224
- ])
225
- .filter(
226
- (record) =>
227
- record.stage === "values_ready" &&
228
- record.source === "fresh_socket",
229
- )
230
- .map((record) => String(record.stream ?? "")),
231
- );
232
- const liveStreamsMatched = requiredLiveStreams.every((stream) =>
233
- liveStreams.has(stream),
499
+ const loadProofRecords = mergeLoadProofRecords(markerLoadProofRecords);
500
+ const coherentProof = coherentPerformanceProof(
501
+ performanceRecords,
502
+ loadProofRecords,
503
+ expected && SURFACE_STAGES.has(expected.stage) ? [expected.stage] : [],
504
+ requiredLiveStreams,
505
+ node.wait_for_lifecycle === undefined
506
+ ? null
507
+ : String(node.wait_for_lifecycle),
508
+ node.wait_for_content_variant === undefined
509
+ ? null
510
+ : String(node.wait_for_content_variant),
234
511
  );
235
- if (stageMatched && liveStreamsMatched) return;
512
+ const stageMatched =
513
+ expected === null ||
514
+ performanceRecords.some(
515
+ (record) =>
516
+ Object.entries(expected).every(
517
+ ([key, value]) =>
518
+ key === "content_variant"
519
+ ? contentVariantSatisfies(
520
+ String(record.content_variant ?? ""),
521
+ value,
522
+ )
523
+ : String(record[key] ?? "") === value,
524
+ ) &&
525
+ (coherentProof.demand === null ||
526
+ sameIdentity(record, coherentProof.demand)),
527
+ );
528
+ const coherenceMatched =
529
+ coherentProof.status === "not_required" || coherentProof.status === "pass";
530
+ if (stageMatched && coherenceMatched) return;
236
531
  if (Date.now() >= deadline) {
237
532
  throw new Error(
238
533
  `Timed out waiting ${timeoutMs}ms for ${MARKER} stage ${JSON.stringify(expected)} and live streams ${JSON.stringify(requiredLiveStreams)}.`,
@@ -271,13 +566,19 @@ function startupMeasurements(records) {
271
566
  }
272
567
 
273
568
  function perpsBootstrapBoundary(homepageRecords, loadProofRecords) {
274
- const demandTimes = homepageRecords
569
+ const demands = homepageRecords
275
570
  .filter((record) => record.stage === "surface_demand")
276
- .map((record) => Number(record.monotonic_ms))
277
- .filter(Number.isFinite);
278
- const firstDemandAt = demandTimes.length > 0 ? Math.min(...demandTimes) : null;
571
+ .filter((record) => Number.isFinite(Number(record.monotonic_ms)))
572
+ .sort((left, right) => Number(left.monotonic_ms) - Number(right.monotonic_ms));
573
+ const demand = demands[0] ?? null;
574
+ const firstDemandAt = demand === null ? null : Number(demand.monotonic_ms);
279
575
  const bootstrapTimes = loadProofRecords
280
- .filter((record) => record.stage === "perps_bootstrap_start")
576
+ .filter(
577
+ (record) =>
578
+ record.stage === "perps_bootstrap_start" &&
579
+ demand !== null &&
580
+ sameIdentity(record, demand, LOAD_PROOF_BASE_IDENTITY_FIELDS),
581
+ )
281
582
  .map((record) => Number(record.monotonic_ms))
282
583
  .filter(
283
584
  (value) =>
@@ -379,6 +680,13 @@ function frameTime(record) {
379
680
 
380
681
  function frameIsFresh(record) {
381
682
  if (record.fresh_for_lifecycle === false) return false;
683
+ if (record.source === "retained_market_context") {
684
+ return (
685
+ record.lifecycle === "account_switch" &&
686
+ !isAccountContentVariant(record.content_variant) &&
687
+ record.fresh_for_lifecycle === true
688
+ );
689
+ }
382
690
  return (
383
691
  FRESH_SOURCES.has(record.source) ||
384
692
  ((record.source === "resident_state" || record.source === "memory_cache") &&
@@ -395,13 +703,8 @@ function frameIsCached(record) {
395
703
  }
396
704
 
397
705
  function visibleFrameGroups(records) {
398
- const demandLifecycles = new Map(
399
- records
400
- .filter((record) => record.stage === "surface_demand")
401
- .map((record) => [
402
- String(record.demand_id ?? ""),
403
- record.lifecycle ?? "unknown",
404
- ]),
706
+ const demands = records.filter(
707
+ (record) => record.stage === "surface_demand",
405
708
  );
406
709
  const groups = new Map();
407
710
  for (const record of records) {
@@ -409,12 +712,13 @@ function visibleFrameGroups(records) {
409
712
  const at = frameTime(record);
410
713
  if (at === null) continue;
411
714
  const demandId = String(record.demand_id ?? "");
412
- const key = `${demandId}:${at}`;
715
+ const key = `${identityKey(record)}:${at}`;
716
+ const demand = demands.find((candidate) => sameIdentity(candidate, record));
413
717
  const group = groups.get(key) ?? {
414
718
  at,
415
719
  demandId,
416
- lifecycle:
417
- record.lifecycle ?? demandLifecycles.get(demandId) ?? "unknown",
720
+ demand,
721
+ lifecycle: record.lifecycle ?? demand?.lifecycle ?? "unknown",
418
722
  records: [],
419
723
  };
420
724
  group.records.push(record);
@@ -451,23 +755,29 @@ function frameGroupSatisfies(group, requiredVariants, predicate) {
451
755
 
452
756
  function cacheTakeoverMeasurement(records, requiredContentVariants = []) {
453
757
  const groups = visibleFrameGroups(records);
454
- const cached = groups.find((group) =>
455
- frameGroupSatisfies(group, requiredContentVariants, frameIsCached),
758
+ const cached = groups.find(
759
+ (group) =>
760
+ group.demand &&
761
+ frameGroupSatisfies(group, requiredContentVariants, frameIsCached),
456
762
  );
457
763
  const fresh = cached
458
764
  ? groups.find(
459
765
  (group) =>
460
766
  group.at > cached.at &&
767
+ group.demand &&
768
+ sameIdentity(group.demand, cached.demand) &&
461
769
  frameGroupSatisfies(group, requiredContentVariants, frameIsFresh),
462
770
  )
463
771
  : null;
464
772
  const cacheHydratedValues = records
465
- .filter((record) => record.stage === "disk_cache_hydrated")
466
- .map((record) => Number(record.monotonic_ms))
467
773
  .filter(
468
- (value) =>
469
- Number.isFinite(value) && (cached === undefined || value <= cached.at),
470
- );
774
+ (record) =>
775
+ record.stage === "disk_cache_hydrated" &&
776
+ cached !== undefined &&
777
+ sameIdentity(record, cached.demand),
778
+ )
779
+ .map((record) => Number(record.monotonic_ms))
780
+ .filter((value) => Number.isFinite(value) && value <= cached.at);
471
781
  const cacheHydratedAt =
472
782
  cacheHydratedValues.length > 0 ? Math.max(...cacheHydratedValues) : null;
473
783
  const failureReason = !cached
@@ -511,29 +821,42 @@ function visibleMeasurements(records, requiredFreshContentVariants = []) {
511
821
  return demands.map((demand) => {
512
822
  const demandId = String(demand.demand_id ?? "");
513
823
  const startedAt = Number(demand.monotonic_ms);
514
- const belongsToDemand = (record) =>
515
- String(record.demand_id ?? "") === demandId &&
516
- ["account_generation", "context_generation"].every(
517
- (key) =>
518
- demand[key] === undefined ||
519
- record[key] === undefined ||
520
- String(record[key]) === String(demand[key]),
521
- );
824
+ const belongsToDemand = (record) => sameIdentity(record, demand);
825
+ const afterDemand = (record) => {
826
+ const at = performanceRecordTime(record);
827
+ return at !== null && Number.isFinite(startedAt) && at >= startedAt;
828
+ };
522
829
  const frames = records.filter(
523
830
  (record) =>
524
- record.stage === "next_frame_checkpoint" && belongsToDemand(record),
831
+ record.stage === "next_frame_checkpoint" &&
832
+ belongsToDemand(record) &&
833
+ afterDemand(record),
525
834
  );
526
835
  const commits = records.filter(
527
- (record) => record.stage === "react_commit" && belongsToDemand(record),
528
- );
529
- const firstVisibleBoundary = records.find(
530
- (record) =>
531
- record.stage === "surface_resolved_recorded" && belongsToDemand(record),
532
- );
533
- const freshVisibleBoundary = records.find(
534
836
  (record) =>
535
- record.stage === "surface_live_recorded" && belongsToDemand(record),
837
+ record.stage === "react_commit" &&
838
+ belongsToDemand(record) &&
839
+ afterDemand(record),
536
840
  );
841
+ const firstVisibleBoundary = records
842
+ .filter(
843
+ (record) =>
844
+ record.stage === "surface_resolved_recorded" &&
845
+ belongsToDemand(record) &&
846
+ afterDemand(record),
847
+ )
848
+ .sort((left, right) => frameTime(left) - frameTime(right))[0];
849
+ const firstVisibleBoundaryAt = frameTime(firstVisibleBoundary ?? {});
850
+ const freshVisibleBoundary = records
851
+ .filter(
852
+ (record) =>
853
+ record.stage === "surface_live_recorded" &&
854
+ belongsToDemand(record) &&
855
+ afterDemand(record) &&
856
+ (firstVisibleBoundaryAt === null ||
857
+ frameTime(record) >= firstVisibleBoundaryAt),
858
+ )
859
+ .sort((left, right) => frameTime(left) - frameTime(right))[0];
537
860
  const frameTimes = frames
538
861
  .map((record) =>
539
862
  Number(record.frame_checkpoint_monotonic_ms ?? record.monotonic_ms),
@@ -601,6 +924,11 @@ function visibleMeasurements(records, requiredFreshContentVariants = []) {
601
924
  const dataAges = frames
602
925
  .map((record) => Number(record.data_age_ms))
603
926
  .filter(Number.isFinite);
927
+ const deliveryRecords = [
928
+ ...frames,
929
+ firstVisibleBoundary,
930
+ freshVisibleBoundary,
931
+ ].filter(Boolean);
604
932
  return {
605
933
  demandId,
606
934
  lifecycle: demand.lifecycle ?? "unknown",
@@ -625,10 +953,15 @@ function visibleMeasurements(records, requiredFreshContentVariants = []) {
625
953
  ? roundMs(freshVisibleAt - startedAt)
626
954
  : null,
627
955
  deliverySources: [
628
- ...new Set(frames.map((record) => String(record.source ?? "unknown"))),
956
+ ...new Set(
957
+ deliveryRecords
958
+ .map((record) => String(record.source ?? ""))
959
+ .filter(Boolean),
960
+ ),
629
961
  ],
630
962
  contentVariant:
631
- frames.find((record) => record.content_variant)?.content_variant ??
963
+ deliveryRecords.find((record) => record.content_variant)
964
+ ?.content_variant ??
632
965
  null,
633
966
  maxDataAgeMs: dataAges.length > 0 ? Math.max(...dataAges) : null,
634
967
  };
@@ -694,18 +1027,31 @@ function socketPipelineMeasurements(records) {
694
1027
  return sockets.flatMap((socket) => {
695
1028
  const deliveryId = String(socket.delivery_id);
696
1029
  const socketAt = Number(socket.monotonic_ms);
697
- const commit = records.find(
698
- (record) =>
699
- record.stage === "react_commit" &&
700
- String(record.delivery_id ?? "") === deliveryId,
701
- );
702
- const frame = records.find(
703
- (record) =>
704
- record.stage === "next_frame_checkpoint" &&
705
- String(record.delivery_id ?? "") === deliveryId,
706
- );
707
- if (!commit || !frame || !Number.isFinite(socketAt)) return [];
1030
+ if (!Number.isFinite(socketAt)) return [];
1031
+ const commit = records
1032
+ .filter(
1033
+ (record) =>
1034
+ record.stage === "react_commit" &&
1035
+ String(record.delivery_id ?? "") === deliveryId &&
1036
+ sameIdentity(record, socket) &&
1037
+ Number(record.monotonic_ms) >= socketAt,
1038
+ )
1039
+ .sort(
1040
+ (left, right) => Number(left.monotonic_ms) - Number(right.monotonic_ms),
1041
+ )[0];
1042
+ if (!commit) return [];
708
1043
  const commitAt = Number(commit.monotonic_ms);
1044
+ const frame = records
1045
+ .filter(
1046
+ (record) =>
1047
+ record.stage === "next_frame_checkpoint" &&
1048
+ String(record.delivery_id ?? "") === deliveryId &&
1049
+ sameIdentity(record, socket) &&
1050
+ frameTime(record) !== null &&
1051
+ frameTime(record) >= commitAt,
1052
+ )
1053
+ .sort((left, right) => frameTime(left) - frameTime(right))[0];
1054
+ if (!frame) return [];
709
1055
  const frameAt = Number(
710
1056
  frame.frame_checkpoint_monotonic_ms ?? frame.monotonic_ms,
711
1057
  );
@@ -714,14 +1060,14 @@ function socketPipelineMeasurements(records) {
714
1060
  (record) =>
715
1061
  record.stage === "subscriber_delivery" &&
716
1062
  String(record.delivery_id ?? "") === deliveryId &&
1063
+ sameIdentity(record, socket) &&
1064
+ Number(record.monotonic_ms) >= socketAt &&
717
1065
  Number(record.monotonic_ms) <= commitAt,
718
1066
  )
719
1067
  .map((record) => Number(record.monotonic_ms))
720
1068
  .filter(Number.isFinite);
721
- const subscriberAt =
722
- subscriberCandidates.length > 0
723
- ? Math.max(...subscriberCandidates)
724
- : socketAt;
1069
+ if (subscriberCandidates.length === 0) return [];
1070
+ const subscriberAt = Math.max(...subscriberCandidates);
725
1071
  return [
726
1072
  {
727
1073
  deliveryId,
@@ -757,14 +1103,20 @@ function firstFreshDeliveryChecks(records, requirements) {
757
1103
  record.delivery_id,
758
1104
  );
759
1105
  const delivery = socket
760
- ? records.find(
761
- (record) =>
762
- record.stage === "subscriber_delivery" &&
763
- record.delivery_id === socket.delivery_id &&
764
- record.stream === stream &&
765
- record.lifecycle === socket.lifecycle &&
766
- Number(record.throttle_ms ?? 0) === subscriberThrottleMs,
767
- )
1106
+ ? records
1107
+ .filter(
1108
+ (record) =>
1109
+ record.stage === "subscriber_delivery" &&
1110
+ record.delivery_id === socket.delivery_id &&
1111
+ record.stream === stream &&
1112
+ sameIdentity(record, socket) &&
1113
+ Number(record.monotonic_ms) >= Number(socket.monotonic_ms) &&
1114
+ Number(record.throttle_ms ?? 0) === subscriberThrottleMs,
1115
+ )
1116
+ .sort(
1117
+ (left, right) =>
1118
+ Number(left.monotonic_ms) - Number(right.monotonic_ms),
1119
+ )[0]
768
1120
  : null;
769
1121
  const socketAt = Number(socket?.monotonic_ms);
770
1122
  const subscriberAt = Number(delivery?.monotonic_ms);
@@ -797,6 +1149,7 @@ function summarize(
797
1149
  bytesScanned,
798
1150
  requiredFreshContentVariants = [],
799
1151
  firstFreshDeliveryRequirements = [],
1152
+ includeCacheTakeover = false,
800
1153
  ) {
801
1154
  const measurements = visibleMeasurements(
802
1155
  records,
@@ -849,10 +1202,9 @@ function summarize(
849
1202
  monotonicValues.length > 0 ? Math.max(...monotonicValues) : null,
850
1203
  visibleMeasurements: measurements,
851
1204
  visibleMeasurementCohorts: visibleMeasurementCohorts(measurements),
852
- cacheTakeoverMeasurement: cacheTakeoverMeasurement(
853
- records,
854
- requiredFreshContentVariants,
855
- ),
1205
+ cacheTakeoverMeasurement: includeCacheTakeover
1206
+ ? cacheTakeoverMeasurement(records, requiredFreshContentVariants)
1207
+ : { status: "not_required" },
856
1208
  socketPipelineMeasurements: socketPipelineMeasurements(records),
857
1209
  firstFreshDeliveryChecks: firstFreshDeliveryChecks(
858
1210
  records,
@@ -885,15 +1237,29 @@ export async function capturePerpsPerformance(input) {
885
1237
  await mkdir(artifactsDir, { recursive: true });
886
1238
 
887
1239
  if (phase === "start") {
888
- const offset = await fileSize(sourceFile);
889
- const existingContent =
890
- offset > 0 ? (await readFile(sourceFile)).toString("utf8") : "";
1240
+ const sourceIdentity = await fileState(sourceFile);
1241
+ const offset = sourceIdentity?.size ?? 0;
1242
+ const lookbackStart = Math.max(0, offset - BOOTSTRAP_LOOKBACK_BYTES);
1243
+ const existingContent = sourceIdentity
1244
+ ? (
1245
+ await readFileRange(sourceFile, lookbackStart, offset - lookbackStart)
1246
+ ).toString("utf8")
1247
+ : "";
1248
+ const boundaryStart = Math.max(0, offset - CAPTURE_BOUNDARY_BYTES);
1249
+ const sourceBoundary = sourceIdentity
1250
+ ? captureBoundaryBytes(
1251
+ boundaryStart,
1252
+ await readFileRange(sourceFile, boundaryStart, offset - boundaryStart),
1253
+ )
1254
+ : null;
891
1255
  await writeFile(
892
1256
  stateFile,
893
1257
  `${JSON.stringify(
894
1258
  {
895
1259
  sourcePath,
896
1260
  offset,
1261
+ sourceIdentity,
1262
+ sourceBoundary,
897
1263
  captureStartedAtEpochMs: Date.now(),
898
1264
  perpsBootstrapStartRecord:
899
1265
  latestPerpsBootstrapStartRecord(existingContent),
@@ -918,6 +1284,19 @@ export async function capturePerpsPerformance(input) {
918
1284
  state.sourcePath !== sourcePath ||
919
1285
  !Number.isInteger(state.offset) ||
920
1286
  state.offset < 0 ||
1287
+ !(
1288
+ state.sourceIdentity === null ||
1289
+ (state.sourceIdentity &&
1290
+ Number.isInteger(state.sourceIdentity.device) &&
1291
+ Number.isInteger(state.sourceIdentity.inode))
1292
+ ) ||
1293
+ !(
1294
+ state.sourceBoundary === null ||
1295
+ (state.sourceBoundary &&
1296
+ Number.isInteger(state.sourceBoundary.start) &&
1297
+ Number.isInteger(state.sourceBoundary.length) &&
1298
+ typeof state.sourceBoundary.sha256 === "string")
1299
+ ) ||
921
1300
  !Number.isFinite(state.captureStartedAtEpochMs)
922
1301
  ) {
923
1302
  throw new Error(
@@ -928,11 +1307,11 @@ export async function capturePerpsPerformance(input) {
928
1307
  await waitForPerformanceRecord({
929
1308
  node,
930
1309
  sourceFile,
931
- offset: state.offset,
1310
+ state,
932
1311
  });
933
1312
 
934
- const content = await readFile(sourceFile);
935
- const offset = state.offset <= content.length ? state.offset : 0;
1313
+ const content = await readCaptureSource(sourceFile, state);
1314
+ const offset = state.offset;
936
1315
  const segment = content.subarray(offset).toString("utf8");
937
1316
  const segmentLines = segment.split(/\r?\n/u);
938
1317
  const lines = segmentLines
@@ -959,10 +1338,7 @@ export async function capturePerpsPerformance(input) {
959
1338
  .map((line) => parseRecord(line, LOAD_PROOF_MARKER))
960
1339
  .filter(Boolean),
961
1340
  ];
962
- const loadProofRecords = mergeLoadProofRecords([
963
- ...markerLoadProofRecords,
964
- ...existingLiveStreamRecords(segmentLines, markerLoadProofRecords),
965
- ]);
1341
+ const loadProofRecords = mergeLoadProofRecords(markerLoadProofRecords);
966
1342
  const requireRecords = node.require_records !== false;
967
1343
  const requiredStages = Array.isArray(node.required_stages)
968
1344
  ? node.required_stages.map(String)
@@ -1048,17 +1424,19 @@ export async function capturePerpsPerformance(input) {
1048
1424
  const requiredLiveStreams = Array.isArray(node.required_live_streams)
1049
1425
  ? node.required_live_streams.map(String)
1050
1426
  : [];
1051
- const presentLiveStreams = new Set(
1052
- loadProofRecords
1053
- .filter(
1054
- (record) =>
1055
- record.stage === "values_ready" && record.source === "fresh_socket",
1056
- )
1057
- .map((record) => String(record.stream ?? "")),
1058
- );
1059
- const missingLiveStreams = requiredLiveStreams.filter(
1060
- (stream) => !presentLiveStreams.has(stream),
1427
+ const coherentProof = coherentPerformanceProof(
1428
+ records,
1429
+ loadProofRecords,
1430
+ requiredStages,
1431
+ requiredLiveStreams,
1432
+ node.wait_for_lifecycle === undefined
1433
+ ? null
1434
+ : String(node.wait_for_lifecycle),
1435
+ node.wait_for_content_variant === undefined
1436
+ ? null
1437
+ : String(node.wait_for_content_variant),
1061
1438
  );
1439
+ const missingLiveStreams = coherentProof.missingLiveStreams;
1062
1440
  const measuredPerpsBootstrapBoundary = perpsBootstrapBoundary(
1063
1441
  records,
1064
1442
  loadProofRecords,
@@ -1088,6 +1466,7 @@ export async function capturePerpsPerformance(input) {
1088
1466
  missingFreshContentVariants.length === 0 &&
1089
1467
  failedFirstFreshDeliveries.length === 0 &&
1090
1468
  missingLiveStreams.length === 0 &&
1469
+ coherentProof.status !== "fail" &&
1091
1470
  (!requirePerpsBootstrapStartBeforeDemand ||
1092
1471
  measuredPerpsBootstrapBoundary.status === "pass") &&
1093
1472
  (!requireCacheBeforeFresh || cacheTakeover.status === "pass")
@@ -1102,6 +1481,9 @@ export async function capturePerpsPerformance(input) {
1102
1481
  missingFreshContentVariants,
1103
1482
  failedFirstFreshDeliveries,
1104
1483
  missingLiveStreams,
1484
+ coherentSurfaceAndLive: coherentProof.status,
1485
+ coherentIdentity: coherentProof.identity,
1486
+ coherentSurfaceSequence: coherentProof.sequence,
1105
1487
  perpsBootstrapStartBeforeDemand: requirePerpsBootstrapStartBeforeDemand
1106
1488
  ? measuredPerpsBootstrapBoundary.status
1107
1489
  : "not_required",
@@ -1120,6 +1502,7 @@ export async function capturePerpsPerformance(input) {
1120
1502
  content.length - offset,
1121
1503
  requiredFreshContentVariants,
1122
1504
  firstFreshDeliveryRequirements,
1505
+ requireCacheBeforeFresh,
1123
1506
  ),
1124
1507
  captureWindow: {
1125
1508
  startedAtEpochMs: state.captureStartedAtEpochMs,
@@ -1149,6 +1532,11 @@ export async function capturePerpsPerformance(input) {
1149
1532
  `Missing required ${STARTUP_MARKER} stages: ${missingStartupStages.join(", ")}.`,
1150
1533
  );
1151
1534
  }
1535
+ if (coherentProof.status === "fail") {
1536
+ throw new Error(
1537
+ `Required ${MARKER} surface stages and live streams did not form one ordered identity-coherent demand tuple.`,
1538
+ );
1539
+ }
1152
1540
  if (
1153
1541
  requirePerpsBootstrapStartBeforeDemand &&
1154
1542
  measuredPerpsBootstrapBoundary.status !== "pass"