@mark1russell7/harness 0.12.4 → 0.13.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 CHANGED
@@ -294,9 +294,16 @@ Each run starts from kernels that keep nothing from the run before it (`lab.forg
294
294
  - **A detection by the program** (`application.ts`). The kernel has no report of it. Thus the program of the observer writes a line before each of its own acts, and the kernel stamps each act on the socket.
295
295
  - The program writes `ping` before each ping of its heartbeat. The kernel stamps the write of the ping (`tx`).
296
296
  - The reference is the first ping that got no answer (`ping-sent`): no segment with data reached the socket after its write, up to the detection. Its write starts the timer of the heartbeat that the fault met. The fault can come at any time, and its stamps are not necessary.
297
- - The program writes `drop` before it drops the connection itself. The detection is the kernel's stamp of that drop: the write of its close frame, or the change of its socket out of ESTABLISHED. Without such a record in the handling time of the program (`DROP_HANDLING`, 1.5 ms), it is the stamp of the line. Where δ_abs is longer, the window is δ_abs.
297
+ - The program writes `drop` before it drops the connection itself. The detection is the kernel's stamp of that drop: the write of its close frame, or the change of its socket out of ESTABLISHED. Without such a record in the handling time of the program (`DROP_HANDLING`, 1.5 ms), it is the stamp of the line. Where the pairing window of the run is longer, the window is that window.
298
298
  - The handling time is not δ_abs. δ_abs is the noise of the pipeline, from a reset. The handling is the time of the code of the program, from the firing of its timer to its act.
299
299
  - In 585 drops with a close frame in CI, the write came a median of 0.652 ms after the `drop` line, and 1.017 ms at the most. Two of them came more than the δ_abs of 1 ms after it. Each failed its cell, with its time in the band. These are the runs 39390222333 and 39903020657 of the client repository. The bound is that maximum and a margin of 0.48 ms.
300
+ - **The pairing window of a run** (`pairingOf`, SYS-25). On a runner of GitHub, the jitter of a program can be longer than the δ_abs of 1 ms. Thus each run measures that jitter before its fault (`jitterOf`, `Run.jitter`).
301
+ - An act is a `write` line or a `ping` line on the connection, before the start of the fault. A fault with no stamp ends the acts at the reply of the client.
302
+ - The delay of an act goes from its line to the kernel's stamp of the first write of data on the socket after it. That write must come before the next act and before the fault. An act without one does not count.
303
+ - The bound is the longest delay of the run. The window of each pairing of the run (a `ping` line and a `drop` line) is δ_abs, or the bound when the bound is longer.
304
+ - The window comes from the same run, not from a constant. The rule of one miss stays (the decision of 2026-10-19): a pair outside the window of its run is still a finding.
305
+ - Each measurement gives its bound and its window (`Measured.pairing`), and the runner of the cells sums them in `summary.ndjson` (`pairingsOf`). A run from before SYS-25 has no jitter record. It reads as a bound of null, thus its window is δ_abs: 1 ms on a calibrated runner.
306
+ - In the records of the nightly run 40446582383, a bound was longer than 1 ms only in the cells of the `ws` class. Their first write (a `hello`) came up to 1.519 ms after its line. In the other cells the bound was 0.058 ms to 0.955 ms.
300
307
  - A drop counts when it comes before each report of the kernel. A report of the kernel that comes first is the detection, and the drop after it is not.
301
308
  - The second view is the stamps of the program: from its `ping` line to its `drop` line. The steps are the later pings, each from the reference.
302
309
  - The lines of a client name the socket by its local address (`local`), and the lines of a server by its peer (`peer`). For the server, the lines are the lines of the target. A line whose address is null is about a try that did not open.
@@ -354,9 +361,10 @@ Each run starts from kernels that keep nothing from the run before it (`lab.forg
354
361
  `verdictOf(prediction, runs)` (`verdict.ts`) judges a cell:
355
362
 
356
363
  - **Containment.** Each run lands in [T_lo − δ_abs, T_hi + δ_abs]. `NOISE` (δ_abs) is 4 ms, from the calibration of the first environment: the worst reset took 1.141 ms, and δ_abs is one jiffy at the minimum.
357
- - **δ_abs of an environment.** A cell can give the δ_abs of its environment (`Cell.noise`). Stage 0 measures it in each environment. On a hosted runner of GitHub at HZ 1000, the worst reset took 0.147 ms, thus δ_abs is one jiffy, 1 ms. These read it (`noiseOf`): the bands, the pairing of a program line with its kernel record, and the drop of a program (with `DROP_HANDLING`).
364
+ - **δ_abs of an environment.** A cell can give the δ_abs of its environment (`Cell.noise`). Stage 0 measures it in each environment. On a hosted runner of GitHub at HZ 1000, the worst reset took 0.147 ms, thus δ_abs is one jiffy, 1 ms. These read it (`noiseOf`): the bands, and the rule of a late timer.
365
+ - **The pairing of a program line.** The pairing of a program line with its kernel record reads the window of its run (`pairingOf`). That window is δ_abs, or the jitter bound of the run when it is longer.
358
366
  - **The injector has its own bound.** A fault that the injector commits or lifts late makes a run void. That bound is `INJECT` (4 ms), not δ_abs. Stage 0 measures the commit apart. On a hosted runner it took up to 2.75 ms at 4 environments.
359
- - **The drop of a program has its own bound.** The pairing of a `drop` line with its act uses `DROP_HANDLING` (1.5 ms), or δ_abs when δ_abs is longer. The band of a drop in the cells adds `DROP_HANDLING` to its high bound.
367
+ - **The drop of a program has its own bound.** The pairing of a `drop` line with its act uses `DROP_HANDLING` (1.5 ms), or the window of the run when that window is longer. The band of a drop in the cells adds `DROP_HANDLING` to its high bound.
360
368
  - **Median equivalence.** The order-statistic interval of the median must be in the band, made 5 % wider.
361
369
  - **Extension.** A median across the edge of the band extends the cell from 11 runs to 22, then 44. Then the verdict is inconclusive.
362
370
  - **Recovery.** The recovery after a stall gets the same test as a detection, by its band. A detection is then a finding.
@@ -1046,6 +1046,18 @@ interface ProbeEvent {
1046
1046
  readonly t: number;
1047
1047
  readonly [field: string]: unknown;
1048
1048
  }
1049
+ /**
1050
+ * A jitter record tells how late the kernel stamped the acts of a program after their lines, in
1051
+ * one run. An act is a `write` line or a `ping` line on the connection of the run, before the
1052
+ * fault. Its delay goes from the line to the kernel's stamp of the first write of data on the
1053
+ * socket after it. That write must come before the next act and before the fault.
1054
+ */
1055
+ interface Jitter {
1056
+ /** This count is the number of acts that had a write in their window. */
1057
+ readonly acts: number;
1058
+ /** This time is the longest delay of those acts. It is null when the run has no such act. */
1059
+ readonly bound: Quantity | null;
1060
+ }
1049
1061
  /** A run is one run of a cell, as the harness records it. */
1050
1062
  interface Run {
1051
1063
  readonly environment: number;
@@ -1082,6 +1094,13 @@ interface Run {
1082
1094
  * late timer is in time. A run without it keeps the rule in jiffies, as the runs before 0.9.0.
1083
1095
  */
1084
1096
  readonly hz?: number;
1097
+ /**
1098
+ * This record is the jitter of the program of the observer in the run (`jitterOf`). The pairing
1099
+ * window of the run is δ_abs of its cell, or the bound of the jitter when the bound is longer
1100
+ * (`pairingOf`). A record from before SYS-25 has no jitter. It reads as a bound of null, thus
1101
+ * its window is δ_abs of its cell: 1 ms on a calibrated runner.
1102
+ */
1103
+ readonly jitter?: Jitter;
1085
1104
  /** These are the addresses and the namespaces of a topology, which the measurement of a run reads. */
1086
1105
  readonly topology?: RunTopology;
1087
1106
  /** These are the lines of the routers of a topology from the start to the end of the run. */
@@ -1143,5 +1162,5 @@ interface RunTopology {
1143
1162
  }>>;
1144
1163
  }
1145
1164
  //#endregion
1146
- export { Subject as $, Prediction as A, RequestPrediction as B, KernelRecord as C, MiddleboxForm as D, MiddleboxExpectation as E, Recovers as F, RunPart as G, RttRange as H, Reference as I, SentinelStage as J, RunTopology as K, ReplicaSet as L, ProxyHop as M, ProxyTime as N, Observer as O, Reconnects as P, StageBand as Q, ReplicaSetStage as R, ImageSource as S, MiddleboxEvent as T, Run as U, RouterHop as V, RunGroup as W, ShippedImage as X, Shipped as Y, Stage as Z, HopEvent as _, Cluster as a, latestEndOf as at, HopWrite as b, DriverBand as c, FaultPlace as d, Target as et, Group as f, Hop as g, GroupRole as h, ClientImage as i, isHopPlace as it, ProbeEvent as j, PinnedImage as k, DriverStep as l, GroupPrediction as m, Cell as n, Toxic as nt, ClusterClientAt as o, GroupPlace as p, SentinelEvent as q, Client as r, WsProbe as rt, ClusterStage as s, BuildImage as t, Topology as tt, Fault as u, HopPlace as v, LineMatch as w, HttpProbe as x, HopSignal as y, Replies as z };
1147
- //# sourceMappingURL=cell-jEkGFgGL.d.ts.map
1165
+ export { StageBand as $, PinnedImage as A, Replies as B, Jitter as C, MiddleboxExpectation as D, MiddleboxEvent as E, Reconnects as F, RunGroup as G, RouterHop as H, Recovers as I, SentinelEvent as J, RunPart as K, Reference as L, ProbeEvent as M, ProxyHop as N, MiddleboxForm as O, ProxyTime as P, Stage as Q, ReplicaSet as R, ImageSource as S, LineMatch as T, RttRange as U, RequestPrediction as V, Run as W, Shipped as X, SentinelStage as Y, ShippedImage as Z, HopEvent as _, Cluster as a, isHopPlace as at, HopWrite as b, DriverBand as c, FaultPlace as d, Subject as et, Group as f, Hop as g, GroupRole as h, ClientImage as i, WsProbe as it, Prediction as j, Observer as k, DriverStep as l, GroupPrediction as m, Cell as n, Topology as nt, ClusterClientAt as o, latestEndOf as ot, GroupPlace as p, RunTopology as q, Client as r, Toxic as rt, ClusterStage as s, BuildImage as t, Target as tt, Fault as u, HopPlace as v, KernelRecord as w, HttpProbe as x, HopSignal as y, ReplicaSetStage as z };
1166
+ //# sourceMappingURL=cell-D2QNOxE8.d.ts.map
package/build/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { $ as Subject, A as Prediction, B as RequestPrediction, C as KernelRecord, D as MiddleboxForm, E as MiddleboxExpectation, F as Recovers, G as RunPart, H as RttRange, I as Reference, J as SentinelStage, K as RunTopology, L as ReplicaSet, M as ProxyHop, N as ProxyTime, O as Observer, P as Reconnects, Q as StageBand, R as ReplicaSetStage, S as ImageSource, T as MiddleboxEvent, U as Run, V as RouterHop, W as RunGroup, X as ShippedImage, Y as Shipped, Z as Stage, _ as HopEvent, a as Cluster, at as latestEndOf, b as HopWrite, c as DriverBand, d as FaultPlace, et as Target, f as Group, g as Hop, h as GroupRole, i as ClientImage, it as isHopPlace, j as ProbeEvent, k as PinnedImage, l as DriverStep, m as GroupPrediction, n as Cell, nt as Toxic, o as ClusterClientAt, p as GroupPlace, q as SentinelEvent, r as Client, rt as WsProbe, s as ClusterStage, t as BuildImage, tt as Topology, u as Fault, v as HopPlace, w as LineMatch, x as HttpProbe, y as HopSignal, z as Replies } from "./cell-jEkGFgGL.js";
1
+ import { $ as StageBand, A as PinnedImage, B as Replies, C as Jitter, D as MiddleboxExpectation, E as MiddleboxEvent, F as Reconnects, G as RunGroup, H as RouterHop, I as Recovers, J as SentinelEvent, K as RunPart, L as Reference, M as ProbeEvent, N as ProxyHop, O as MiddleboxForm, P as ProxyTime, Q as Stage, R as ReplicaSet, S as ImageSource, T as LineMatch, U as RttRange, V as RequestPrediction, W as Run, X as Shipped, Y as SentinelStage, Z as ShippedImage, _ as HopEvent, a as Cluster, at as isHopPlace, b as HopWrite, c as DriverBand, d as FaultPlace, et as Subject, f as Group, g as Hop, h as GroupRole, i as ClientImage, it as WsProbe, j as Prediction, k as Observer, l as DriverStep, m as GroupPrediction, n as Cell, nt as Topology, o as ClusterClientAt, ot as latestEndOf, p as GroupPlace, q as RunTopology, r as Client, rt as Toxic, s as ClusterStage, t as BuildImage, tt as Target, u as Fault, v as HopPlace, w as KernelRecord, x as HttpProbe, y as HopSignal, z as ReplicaSetStage } from "./cell-D2QNOxE8.js";
2
2
  import { Quantity } from "@mark1russell7/quantity";
3
3
  import "testcontainers";
4
4
  //#region src/application.d.ts
@@ -33,16 +33,16 @@ import "testcontainers";
33
33
  * These are the runs 39390222333 and 39903020657 of the client repository.
34
34
  *
35
35
  * The bound is 1.5 ms: the maximum and a margin of 0.48 ms. The pairing of a drop with its act
36
- * uses it, or δ_abs when δ_abs is longer. The band of a drop adds it to its high bound (the WS
37
- * catalog of the cells). Read the records again after a change to the subject, to Node or to
36
+ * uses it, or the pairing window of the run when that window is longer. The band of a drop adds
37
+ * it to its high bound (the WS catalog of the cells). Read the records again after a change to the subject, to Node or to
38
38
  * the runners.
39
39
  */
40
40
  export declare const DROP_HANDLING: Quantity;
41
41
  /**
42
42
  * A program event is a line of the program of the observer, with the kernel's stamp of its act.
43
43
  * The act is a write, or a change of state of the socket. Without a record of the kernel in its
44
- * window after the line, the instant is the stamp of the line. The window is δ_abs, and for a drop
45
- * it is `DROP_HANDLING` when that is longer.
44
+ * window after the line, the instant is the stamp of the line. The window is the pairing window of
45
+ * the run (`pairingOf`), and for a drop it is `DROP_HANDLING` when that is longer.
46
46
  */
47
47
  interface ProgramEvent {
48
48
  readonly line: ProbeEvent;
@@ -79,12 +79,19 @@ export declare const closeOrExit: (line: ProbeEvent, left: Quantity | null, exit
79
79
  };
80
80
  /**
81
81
  * This function tells how a drop differs from the way that its prediction gives, or gives null.
82
- * A close closes the socket at once: in the handling time of the program (`DROP_HANDLING`), or in
83
- * δ_abs (`delta`) when δ_abs is longer. A close frame is a write, and the program does not close
84
- * the socket at the drop. A peer that answers the close frame can close it, and that is no finding.
82
+ * A close closes the socket at once, in the handling time of the program (`DROP_HANDLING`). If
83
+ * the pairing window of the run (`delta`) is longer, that window is the limit. A close frame is a
84
+ * write, and the program does not close the socket at the drop. A peer that answers the close frame can close it, and that is no finding.
85
85
  */
86
86
  export declare const dropFinding: (expected: "frame" | "close", drop: ProgramEvent, left: Quantity | null, delta?: Quantity, exited?: Quantity) => string | null;
87
- /** This function gives each ping of the program on the connection of the run, with the kernel's stamp of its write. */
87
+ /**
88
+ * This function measures the jitter of a program from its acts before `until`, the start of the
89
+ * fault. An act is a `write` line or a `ping` line on the connection. Its delay goes from the line
90
+ * to the first write of data on the socket after it, before the next act and before `until`. An
91
+ * act with no such write does not count. The bound is the longest delay, to the microsecond.
92
+ */
93
+ export declare const jitterOfLines: (lines: readonly ProbeEvent[], socket: readonly KernelRecord[], local: unknown, until: number) => Jitter;
94
+ /** This function gives each ping of the program on the connection, with the kernel's stamp of its write in the pairing window (`delta`). */
88
95
  export declare const pingsOf: (lines: readonly ProbeEvent[], socket: readonly KernelRecord[], local: unknown, delta?: Quantity) => ProgramEvent[];
89
96
  /**
90
97
  * This function gives the first ping that got no answer: no segment with data reached the socket
@@ -95,7 +102,7 @@ export declare const firstUnanswered: (pings: readonly ProgramEvent[], socket: r
95
102
  * This function gives the first drop of the connection by its program. The kernel stamps it as the
96
103
  * write of a close frame. Or it stamps the change of the socket out of ESTABLISHED: a close or an
97
104
  * abort. That stamp comes in the handling time of the program after the drop line
98
- * (`DROP_HANDLING`), or in δ_abs (`delta`) when δ_abs is longer.
105
+ * (`DROP_HANDLING`). If the pairing window of the run (`delta`) is longer, that window is the limit.
99
106
  */
100
107
  export declare const dropOf: (lines: readonly ProbeEvent[], socket: readonly KernelRecord[], local: unknown, delta?: Quantity) => ProgramEvent | undefined;
101
108
  /** A reconnect reading is what the client did after the detection, from its lines and from the records of the kernel. */
@@ -329,195 +336,6 @@ interface GroupReading {
329
336
  */
330
337
  export declare const measureGroup: (cell: Cell, run: Run) => GroupReading;
331
338
  //#endregion
332
- //#region src/observe.d.ts
333
- /**
334
- * An outcome tells how the wait of a run ended. The socket failed with an errno, or it read the
335
- * end of the file. Or nothing came, or the reply came back after a stall. The observer can also
336
- * close the connection itself (`closed`), or its program can drop it on its own timer (`dropped`).
337
- */
338
- type Outcome = {
339
- readonly kind: "error";
340
- readonly errno: string;
341
- } | {
342
- readonly kind: "eof";
343
- } | {
344
- readonly kind: "silent";
345
- } | {
346
- readonly kind: "answered";
347
- } | {
348
- readonly kind: "closed";
349
- } | {
350
- readonly kind: "dropped";
351
- };
352
- /**
353
- * A request reading is what the second request of an HTTP client met, from the lines of the
354
- * client. It holds the connection of its first try, a new try, and its outcome. `gap` is the time
355
- * from the end of the first reply to the send of the second request.
356
- */
357
- interface RequestReading {
358
- readonly connection: "reused" | "new";
359
- readonly retried: boolean;
360
- readonly error: string | null;
361
- readonly pending: boolean;
362
- readonly gap: Quantity | null;
363
- }
364
- /** A measurement is what one run measured, against the prediction of its cell. */
365
- interface Measured {
366
- readonly environment: number;
367
- readonly index: number;
368
- readonly outcome: Outcome;
369
- /**
370
- * This time is from the reference event of the prediction to the detection, both as the kernel
371
- * stamped them in the records of the prober. It is null when nothing detected the fault.
372
- */
373
- readonly elapsed: Quantity | null;
374
- /** This time is the same interval from the TCP_INFO samples of the client, the second vantage. */
375
- readonly socket: Quantity | null;
376
- /** This time is how long the client took to see the error after the kernel reported it. */
377
- readonly noticed: Quantity | null;
378
- /**
379
- * These are the steps of the kernel after the reference: each keepalive probe, or each firing of
380
- * the RTO timer. After a stall, they are each retransmission from the send, the loss probe first.
381
- */
382
- readonly steps: readonly Quantity[];
383
- /**
384
- * These are the reply times of a measurement-only cell. For each request after the first, a
385
- * sample is the time from its send to the first data after it.
386
- */
387
- readonly samples?: readonly Quantity[];
388
- /** This count is the number of keepalive probes that the kernel sent. */
389
- readonly probes: number;
390
- /** This count is the number of segments that the kernel sent again. */
391
- readonly retransmissions: number;
392
- /** This count is the number of segments that the socket received after the request. */
393
- readonly acks: number;
394
- /** This count is the number of bytes that the client read after the request. */
395
- readonly bytes?: number;
396
- /**
397
- * This time is when a router of the topology forgot the flow of the client. It counts from the
398
- * last segment that the client received before the fault. It is null when no router forgot the flow.
399
- */
400
- readonly forgot?: Quantity | null;
401
- /**
402
- * This time is the first round trip of the socket of the observer. It is the smoothed round trip
403
- * in its first record, which is the sample of the handshake. It is null when no record has it.
404
- */
405
- readonly rtt?: Quantity | null;
406
- /** This record tells what reordering did in a run of a measurement-only cell, from the records of its two ends. */
407
- readonly reordering?: Reordering;
408
- /** These are the times of the proxy of a calibration cell, one for each request and its reply. */
409
- readonly crossings?: Crossings;
410
- /** This record is what a run of a group cell measured: the stages of its timeline, and what became of each write. */
411
- readonly group?: GroupMeasured;
412
- /** This record is what the second request of an HTTP client met, for a cell whose prediction says it. */
413
- readonly request?: RequestReading | null;
414
- /** This record is the time of each later band of a driver cell (`DriverBand.then`). */
415
- readonly driver?: {
416
- readonly steps: readonly DriverStepTime[];
417
- };
418
- /** This record is what the client did after the detection, for a prediction that says when it reconnects. */
419
- readonly reconnect?: ReconnectReading;
420
- /** This record is what the call in flight of a WebSocket client met. */
421
- readonly call?: CallReading;
422
- /**
423
- * This time is from the drop line of the program to the close of its socket by its own side: a
424
- * FIN or an abort. A prediction that says how the program drops (`drop`) gets it. It is null
425
- * when the socket did not close itself in the run. A prediction can say that the client process
426
- * ends with the run (`exits`). Then a close at that end is no close by the program, and `left` is null.
427
- */
428
- readonly left?: Quantity | null;
429
- /**
430
- * This time is from the drop line of the program to the end of the client process. A socket gets
431
- * it when it stayed open until that end. The kernel closed it then, not the program (`exits`).
432
- */
433
- readonly exited?: Quantity;
434
- /** This text is the reason that the run cannot count, or null. A void run is not a pass and not a finding. */
435
- readonly void: string | null;
436
- /** This text tells what in the run disagrees with the prediction, other than its timing, or null. */
437
- readonly finding: string | null;
438
- }
439
- /**
440
- * A reordering record is what reordering, duplicates and losses did to the data of a run. The
441
- * receiver is the client, and the sender is the socket of its peer.
442
- * - `outOfOrder` counts the arrivals at the client beyond a hole, and `duplicates` counts the
443
- * arrivals whose data the client had. The prober reads the two from each arrival, against `rcv_nxt`.
444
- * - An arrival can hold more than one segment. The kernel joins the segments that wait in the
445
- * backlog of a socket while its owner holds it.
446
- * - `ooo` is the count of the kernel of the client in segments (`rcv_ooopack`).
447
- * - `sacked` and `lost` are the most segments that the sender held as SACKed and as lost.
448
- * - `dsacks` is the DSACK blocks that the sender received, and `fast` its fast retransmissions.
449
- * - `degree` is the highest reordering degree of the sender (`tp->reordering`), and `seen` the
450
- * reorderings that it detected (`reord_seen`).
451
- *
452
- * The counts of the kernel are null for a record of the prober before version 0.2.
453
- */
454
- interface Reordering {
455
- readonly outOfOrder: number;
456
- readonly duplicates: number;
457
- readonly ooo: number | null;
458
- readonly sacked: number | null;
459
- readonly lost: number | null;
460
- readonly dsacks: number | null;
461
- readonly fast: number;
462
- readonly degree: number | null;
463
- readonly seen: number | null;
464
- }
465
- /**
466
- * A crossings record is the time of a proxy for each request (`up`) and for each reply (`down`).
467
- * The time of a request starts at its arrival on the socket toward the client. It stops at the
468
- * write on the socket toward the target. The time of a reply goes the other way. A write is a
469
- * `tx` record of the prober.
470
- */
471
- interface Crossings {
472
- readonly hop: string;
473
- readonly up: readonly Quantity[];
474
- readonly down: readonly Quantity[];
475
- }
476
- /** A socket place is a socket of a run: its namespace and its cookie. */
477
- interface SocketPlace {
478
- readonly netns: number;
479
- readonly cookie: number;
480
- }
481
- /**
482
- * This function finds the socket of the observer of a cell in a run:
483
- * - the client socket, by the address that it connected from, in its namespace.
484
- * - the socket of the target for the same connection, in its namespace.
485
- * - a socket of a proxy of the topology, toward the client or toward the target. Toward the target,
486
- * it is the socket that carries the request, else the first socket that the run opens.
487
- */
488
- export declare const socketOf: (cell: Cell, run: Run) => SocketPlace | undefined;
489
- /** This function gives what reordering did in a run, from the records of the receiver and of the sender. */
490
- export declare const reorderingOf: (receiver: readonly KernelRecord[], sender: readonly KernelRecord[]) => Reordering;
491
- /**
492
- * This function gives the times of a proxy in a run, for each request after the first. The time
493
- * of a request starts at its arrival on the socket of the proxy toward the client. It stops at the
494
- * next write on the socket toward the target. The time of its reply starts at its arrival on the
495
- * socket toward the target, and it stops at the next write toward the client. A request without
496
- * each record gives no time.
497
- */
498
- export declare const crossingsOf: (run: Run, hop: string, toClient: SocketPlace | undefined, toTarget: SocketPlace | undefined) => Crossings;
499
- /**
500
- * This function reads one run against its cell, from the records of the kernel first.
501
- * - The socket of the run is the socket of its observer. It is the socket that the client connected
502
- * from, in its namespace, or the socket of the target or of a proxy for that connection.
503
- * - The fault must hold before the event that it must meet. That is before the request goes into
504
- * it, and before the first keepalive probe. A live peer answers that probe, and the answer
505
- * starts the idle time again. A run where the fault was late is void. A run whose records the
506
- * prober lost is also void.
507
- * - For an HTTP client, it also reads what the second request met (`requestOf`). An outcome other
508
- * than the one that the prediction gives is a finding.
509
- */
510
- export declare const measure: (cell: Cell, run: Run) => Measured;
511
- /**
512
- * This function reads the second request of an HTTP client from its lines. Its first try is its
513
- * first `request` line, and each `retry` line is a new try. Its end is its `error` line, or its
514
- * `replied` line. A request with neither is pending. It gives null when the client wrote no try.
515
- *
516
- * A new try that gets no connection writes no `retry` line. Its dial writes a `dial-error` line.
517
- * Thus a `dial-error` line after the first try and before the end is also a new try.
518
- */
519
- export declare const requestOf: (events: readonly ProbeEvent[]) => RequestReading | null;
520
- //#endregion
521
339
  //#region src/verdict.d.ts
522
340
  /** This function gives the words of the outcome of a second request: its connection, a retry, and its end. */
523
341
  export declare const requestWords: (outcome: {
@@ -544,6 +362,35 @@ export declare const INJECT: Quantity;
544
362
  export declare const noiseOf: (cell: {
545
363
  readonly noise?: Quantity | undefined;
546
364
  }) => Quantity;
365
+ /**
366
+ * A pairing is the window of a run in which a line of its program pairs with the kernel's record
367
+ * of its act. `bound` is the jitter of the program that the run measured, or null. `delta` is the
368
+ * window: δ_abs of the cell, or the bound when the bound is longer.
369
+ */
370
+ interface Pairing {
371
+ readonly bound: Quantity | null;
372
+ readonly delta: Quantity;
373
+ }
374
+ /**
375
+ * This function gives the pairing window of a run (SYS-25). On a runner of GitHub, the jitter of
376
+ * a program can be longer than the δ_abs of 1 ms. Thus each run measures it before its fault
377
+ * (`Run.jitter`), and its own measurement widens its window. A run without a jitter record is
378
+ * from before SYS-25. It reads as a bound of null, thus its window is δ_abs. The decision of
379
+ * 2026-10-19 keeps the rule of one miss: a pair that a window misses is still a finding.
380
+ */
381
+ export declare const pairingOf: (cell: {
382
+ readonly noise?: Quantity | undefined;
383
+ }, run: Pick<Run, "jitter">) => Pairing;
384
+ /**
385
+ * This function sums the pairings of the measurements of a cell. It gives the longest bound and
386
+ * the longest window. It also counts the pairings whose window is longer than δ_abs (`noise`). It
387
+ * is null when no measurement has a pairing.
388
+ */
389
+ export declare const pairingsOf: (runs: readonly Measured[], noise?: Quantity) => {
390
+ readonly bound: Quantity | null;
391
+ readonly delta: Quantity;
392
+ readonly widened: number;
393
+ } | null;
547
394
  /**
548
395
  * This function tells if a timer firing came late enough to void a run. A firing two jiffies or
549
396
  * more behind its wheel slot came late because the host stopped a vCPU. With the HZ of the run,
@@ -709,6 +556,207 @@ export declare const verdictOf: (prediction: Prediction, runs: readonly Measured
709
556
  /** This function sums what the group of a group cell did in its counted runs, and tests each stage that has a band. */
710
557
  export declare const groupVerdictOf: (prediction: Prediction, counted: readonly Measured[], delta?: Quantity) => GroupVerdict;
711
558
  //#endregion
559
+ //#region src/observe.d.ts
560
+ /**
561
+ * An outcome tells how the wait of a run ended. The socket failed with an errno, or it read the
562
+ * end of the file. Or nothing came, or the reply came back after a stall. The observer can also
563
+ * close the connection itself (`closed`), or its program can drop it on its own timer (`dropped`).
564
+ */
565
+ type Outcome = {
566
+ readonly kind: "error";
567
+ readonly errno: string;
568
+ } | {
569
+ readonly kind: "eof";
570
+ } | {
571
+ readonly kind: "silent";
572
+ } | {
573
+ readonly kind: "answered";
574
+ } | {
575
+ readonly kind: "closed";
576
+ } | {
577
+ readonly kind: "dropped";
578
+ };
579
+ /**
580
+ * A request reading is what the second request of an HTTP client met, from the lines of the
581
+ * client. It holds the connection of its first try, a new try, and its outcome. `gap` is the time
582
+ * from the end of the first reply to the send of the second request.
583
+ */
584
+ interface RequestReading {
585
+ readonly connection: "reused" | "new";
586
+ readonly retried: boolean;
587
+ readonly error: string | null;
588
+ readonly pending: boolean;
589
+ readonly gap: Quantity | null;
590
+ }
591
+ /** A measurement is what one run measured, against the prediction of its cell. */
592
+ interface Measured {
593
+ readonly environment: number;
594
+ readonly index: number;
595
+ readonly outcome: Outcome;
596
+ /**
597
+ * This time is from the reference event of the prediction to the detection, both as the kernel
598
+ * stamped them in the records of the prober. It is null when nothing detected the fault.
599
+ */
600
+ readonly elapsed: Quantity | null;
601
+ /** This time is the same interval from the TCP_INFO samples of the client, the second vantage. */
602
+ readonly socket: Quantity | null;
603
+ /** This time is how long the client took to see the error after the kernel reported it. */
604
+ readonly noticed: Quantity | null;
605
+ /**
606
+ * These are the steps of the kernel after the reference: each keepalive probe, or each firing of
607
+ * the RTO timer. After a stall, they are each retransmission from the send, the loss probe first.
608
+ */
609
+ readonly steps: readonly Quantity[];
610
+ /**
611
+ * These are the reply times of a measurement-only cell. For each request after the first, a
612
+ * sample is the time from its send to the first data after it.
613
+ */
614
+ readonly samples?: readonly Quantity[];
615
+ /** This count is the number of keepalive probes that the kernel sent. */
616
+ readonly probes: number;
617
+ /** This count is the number of segments that the kernel sent again. */
618
+ readonly retransmissions: number;
619
+ /** This count is the number of segments that the socket received after the request. */
620
+ readonly acks: number;
621
+ /** This count is the number of bytes that the client read after the request. */
622
+ readonly bytes?: number;
623
+ /**
624
+ * This time is when a router of the topology forgot the flow of the client. It counts from the
625
+ * last segment that the client received before the fault. It is null when no router forgot the flow.
626
+ */
627
+ readonly forgot?: Quantity | null;
628
+ /**
629
+ * This time is the first round trip of the socket of the observer. It is the smoothed round trip
630
+ * in its first record, which is the sample of the handshake. It is null when no record has it.
631
+ */
632
+ readonly rtt?: Quantity | null;
633
+ /** This record tells what reordering did in a run of a measurement-only cell, from the records of its two ends. */
634
+ readonly reordering?: Reordering;
635
+ /** These are the times of the proxy of a calibration cell, one for each request and its reply. */
636
+ readonly crossings?: Crossings;
637
+ /** This record is what a run of a group cell measured: the stages of its timeline, and what became of each write. */
638
+ readonly group?: GroupMeasured;
639
+ /** This record is what the second request of an HTTP client met, for a cell whose prediction says it. */
640
+ readonly request?: RequestReading | null;
641
+ /** This record is the time of each later band of a driver cell (`DriverBand.then`). */
642
+ readonly driver?: {
643
+ readonly steps: readonly DriverStepTime[];
644
+ };
645
+ /** This record is what the client did after the detection, for a prediction that says when it reconnects. */
646
+ readonly reconnect?: ReconnectReading;
647
+ /** This record is what the call in flight of a WebSocket client met. */
648
+ readonly call?: CallReading;
649
+ /**
650
+ * This time is from the drop line of the program to the close of its socket by its own side: a
651
+ * FIN or an abort. A prediction that says how the program drops (`drop`) gets it. It is null
652
+ * when the socket did not close itself in the run. A prediction can say that the client process
653
+ * ends with the run (`exits`). Then a close at that end is no close by the program, and `left` is null.
654
+ */
655
+ readonly left?: Quantity | null;
656
+ /**
657
+ * This time is from the drop line of the program to the end of the client process. A socket gets
658
+ * it when it stayed open until that end. The kernel closed it then, not the program (`exits`).
659
+ */
660
+ readonly exited?: Quantity;
661
+ /**
662
+ * This record is the pairing window of the run: the jitter bound that it measured, and the
663
+ * window that its pairings used (`pairingOf`). A run that has a jitter record gets it. Thus a
664
+ * reader can check each pairing of the run again.
665
+ */
666
+ readonly pairing?: Pairing;
667
+ /** This text is the reason that the run cannot count, or null. A void run is not a pass and not a finding. */
668
+ readonly void: string | null;
669
+ /** This text tells what in the run disagrees with the prediction, other than its timing, or null. */
670
+ readonly finding: string | null;
671
+ }
672
+ /**
673
+ * A reordering record is what reordering, duplicates and losses did to the data of a run. The
674
+ * receiver is the client, and the sender is the socket of its peer.
675
+ * - `outOfOrder` counts the arrivals at the client beyond a hole, and `duplicates` counts the
676
+ * arrivals whose data the client had. The prober reads the two from each arrival, against `rcv_nxt`.
677
+ * - An arrival can hold more than one segment. The kernel joins the segments that wait in the
678
+ * backlog of a socket while its owner holds it.
679
+ * - `ooo` is the count of the kernel of the client in segments (`rcv_ooopack`).
680
+ * - `sacked` and `lost` are the most segments that the sender held as SACKed and as lost.
681
+ * - `dsacks` is the DSACK blocks that the sender received, and `fast` its fast retransmissions.
682
+ * - `degree` is the highest reordering degree of the sender (`tp->reordering`), and `seen` the
683
+ * reorderings that it detected (`reord_seen`).
684
+ *
685
+ * The counts of the kernel are null for a record of the prober before version 0.2.
686
+ */
687
+ interface Reordering {
688
+ readonly outOfOrder: number;
689
+ readonly duplicates: number;
690
+ readonly ooo: number | null;
691
+ readonly sacked: number | null;
692
+ readonly lost: number | null;
693
+ readonly dsacks: number | null;
694
+ readonly fast: number;
695
+ readonly degree: number | null;
696
+ readonly seen: number | null;
697
+ }
698
+ /**
699
+ * A crossings record is the time of a proxy for each request (`up`) and for each reply (`down`).
700
+ * The time of a request starts at its arrival on the socket toward the client. It stops at the
701
+ * write on the socket toward the target. The time of a reply goes the other way. A write is a
702
+ * `tx` record of the prober.
703
+ */
704
+ interface Crossings {
705
+ readonly hop: string;
706
+ readonly up: readonly Quantity[];
707
+ readonly down: readonly Quantity[];
708
+ }
709
+ /** A socket place is a socket of a run: its namespace and its cookie. */
710
+ interface SocketPlace {
711
+ readonly netns: number;
712
+ readonly cookie: number;
713
+ }
714
+ /**
715
+ * This function finds the socket of the observer of a cell in a run:
716
+ * - the client socket, by the address that it connected from, in its namespace.
717
+ * - the socket of the target for the same connection, in its namespace.
718
+ * - a socket of a proxy of the topology, toward the client or toward the target. Toward the target,
719
+ * it is the socket that carries the request, else the first socket that the run opens.
720
+ */
721
+ export declare const socketOf: (cell: Cell, run: Run) => SocketPlace | undefined;
722
+ /** This function gives what reordering did in a run, from the records of the receiver and of the sender. */
723
+ export declare const reorderingOf: (receiver: readonly KernelRecord[], sender: readonly KernelRecord[]) => Reordering;
724
+ /**
725
+ * This function gives the times of a proxy in a run, for each request after the first. The time
726
+ * of a request starts at its arrival on the socket of the proxy toward the client. It stops at the
727
+ * next write on the socket toward the target. The time of its reply starts at its arrival on the
728
+ * socket toward the target, and it stops at the next write toward the client. A request without
729
+ * each record gives no time.
730
+ */
731
+ export declare const crossingsOf: (run: Run, hop: string, toClient: SocketPlace | undefined, toTarget: SocketPlace | undefined) => Crossings;
732
+ /**
733
+ * This function reads one run against its cell, from the records of the kernel first.
734
+ * - The socket of the run is the socket of its observer. It is the socket that the client connected
735
+ * from, in its namespace, or the socket of the target or of a proxy for that connection.
736
+ * - The fault must hold before the event that it must meet. That is before the request goes into
737
+ * it, and before the first keepalive probe. A live peer answers that probe, and the answer
738
+ * starts the idle time again. A run where the fault was late is void. A run whose records the
739
+ * prober lost is also void.
740
+ * - For an HTTP client, it also reads what the second request met (`requestOf`). An outcome other
741
+ * than the one that the prediction gives is a finding.
742
+ */
743
+ export declare const measure: (cell: Cell, run: Run) => Measured;
744
+ /**
745
+ * This function measures the jitter of the program of the observer in a run, from its records
746
+ * (`Jitter`). The acts count up to the start of the fault, or up to the reply of the client when
747
+ * the fault has no stamp. A run with no lines of a program, or no socket of the observer, has no act.
748
+ */
749
+ export declare const jitterOf: (cell: Cell, run: Run) => Jitter;
750
+ /**
751
+ * This function reads the second request of an HTTP client from its lines. Its first try is its
752
+ * first `request` line, and each `retry` line is a new try. Its end is its `error` line, or its
753
+ * `replied` line. A request with neither is pending. It gives null when the client wrote no try.
754
+ *
755
+ * A new try that gets no connection writes no `retry` line. Its dial writes a `dial-error` line.
756
+ * Thus a `dial-error` line after the first try and before the end is also a new try.
757
+ */
758
+ export declare const requestOf: (events: readonly ProbeEvent[]) => RequestReading | null;
759
+ //#endregion
712
760
  //#region src/lab.d.ts
713
761
  /**
714
762
  * This time is the interval of the listing of a router, when its hop does not set one. A listing
@@ -1663,5 +1711,5 @@ export declare const spread: (runs: number, environments: number) => number[];
1663
1711
  */
1664
1712
  export declare const runCell: (cell: Cell, say?: (line: string) => void) => Promise<CellResult>;
1665
1713
  //#endregion
1666
- export { type Agent, type BuildImage, type CallReading, type Cell, type CellResult, type Client, type ClientImage, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type Crossings, type Cut, type Decision, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type KernelRecord, type Lab, type LineMatch, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type Outcome, type PinnedImage, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type ReconnectReading, type ReconnectVerdict, type Reconnects, type Recovers, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouterHop, type RttRange, type Run, type RunGroup, type RunPart, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type Stamp, type Status, type StatusRow, type Subject, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
1714
+ export { type Agent, type BuildImage, type CallReading, type Cell, type CellResult, type Client, type ClientImage, type Cluster, type ClusterClientAt, type ClusterLab, type ClusterStage, type Crossings, type Cut, type Decision, type DriverBand, type DriverSocket, type DriverStep, type DriverStepTime, type ErrorOnTheWay, type Fault, type FaultPlace, type FaultSide, type Group, type GroupClient, type GroupLab, type GroupMeasured, type GroupNetworkFault, type GroupPlace, type GroupPrediction, type GroupReading, type GroupRole, type GroupVerdict, type GroupView, type Hop, type HopEvent, type HopPlace, type HopSignal, type HopWrite, type HttpProbe, type ImagePlan, type ImageSource, type Interval, type Jitter, type KernelRecord, type Lab, type LineMatch, type Manifest, type ManifestHop, type Measured, type MemberLine, type MiddleboxEvent, type MiddleboxExpectation, type MiddleboxForm, type NetworkFault, type NodeLine, type Observer, type Outcome, type Pairing, type PinnedImage, type Prediction, type Probe, type ProbeEvent, type ProgramEvent, type ProxyHop, type ProxyTime, type ReconnectReading, type ReconnectVerdict, type Reconnects, type Recovers, type Reference, type Reordering, type ReplicaSet, type ReplicaSetLab, type ReplicaSetStage, type Replies, type RequestPrediction, type RequestReading, type RouterHop, type RttRange, type Run, type RunGroup, type RunPart, type RunTopology, type SentinelEvent, type SentinelStage, type Shipped, type ShippedImage, type SocketPlace, type Spread, type Stage, type StageBand, type StageVerdict, type Stamp, type Status, type StatusRow, type Subject, type Target, type Topology, type Toxic, type Verdict, type WallStamp, type Writes, type WsProbe, isHopPlace, latestEndOf };
1667
1715
  //# sourceMappingURL=index.d.ts.map