@mark1russell7/harness 0.0.0-stage → 0.2.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.
@@ -0,0 +1,546 @@
1
+ import { Quantity } from "@mark1russell7/quantity";
2
+ import { KernelRecord } from "@mark1russell7/prober";
3
+ //#region src/cell.d.ts
4
+ /**
5
+ * A fault is a failure that the harness injects, by the name of its manifestation. Each name is
6
+ * the last segment of the identifier of the manifestation in the corpus:
7
+ * - `blackhole` is two DROP rules in the network namespace of the target. Thus the measurement
8
+ * gets the kernel timers of the client.
9
+ * - `freeze-process` is the cgroup freezer on the target, while its kernel stays up.
10
+ * - `rst` answers the next segment of the client with a reset, from the namespace of the target.
11
+ * It is the reference for the noise of the harness itself.
12
+ * - `stall` is a black hole that stops by itself, `Cell.stall` after the client sends its
13
+ * request. The VM times it. It shows what recovers, and when.
14
+ * - `fin` stops the process of the peer with SIGKILL, while its kernel stays up. The kernel closes its sockets
15
+ * with a FIN, or with a reset when unread data is in the queue.
16
+ * - `unreachable` answers each segment from the observer with an ICMP unreachable (`Cell.icmp`).
17
+ * Linux keeps it as a soft error on an established socket, and it continues to retransmit.
18
+ * - `simplex` drops the segments in one direction only (`Cell.drops`).
19
+ * - `mtu-blackhole` drops each segment to the observer that is longer than `Cell.mtu` bytes.
20
+ * - `netem` is tc netem on the egress of the target (`Cell.netem`): loss, duplication,
21
+ * reordering or corruption. Its outcome is a distribution.
22
+ */
23
+ type Fault = "blackhole" | "freeze-process" | "rst" | "stall" | "fin" | "unreachable" | "simplex" | "mtu-blackhole" | "netem";
24
+ /**
25
+ * A reference is the event that the time of a detector counts from: the event that arms the
26
+ * timer in its machine document. Keepalive counts from the last received segment. The give-up of
27
+ * the retransmissions counts from the first retransmission of the RTO timer, not from the tail
28
+ * loss probe one RTO before it. The request itself meets a reset, thus a reset counts from the
29
+ * send of the client. A FIN counts from the change of state of the socket of the peer when its
30
+ * process dies (`peer-closed`).
31
+ */
32
+ type Reference = "last-received" | "first-retransmission" | "request-sent" | "peer-closed";
33
+ /**
34
+ * This prediction tells when a connection moves again after a stall. That occurs at the first
35
+ * firing of its retransmission timer after the stall stops, and its reply comes back one round
36
+ * trip later.
37
+ */
38
+ interface Recovers {
39
+ /** This count identifies the firing that gets through: the number of firings before it. */
40
+ readonly firing: number;
41
+ /** This time is the earliest return of the reply, from the send of the request. */
42
+ readonly low: Quantity;
43
+ /** This time is the latest return of the reply, from the send of the request. */
44
+ readonly high: Quantity;
45
+ /**
46
+ * This range is where the stall must stop, from the send, so that this firing is the first
47
+ * after it. The range starts after the latest time of the firing before, and it stops before
48
+ * the earliest time of this firing.
49
+ */
50
+ readonly heal: {
51
+ readonly low: Quantity;
52
+ readonly high: Quantity;
53
+ };
54
+ }
55
+ /**
56
+ * A prediction is what a cell predicts. Either a detection occurs in an interval [T_lo, T_hi]
57
+ * after the reference event, or nothing detects the fault in a window. Nothing detects a stall
58
+ * that is shorter than the give-up, and the connection recovers from it. The prediction then also
59
+ * tells when.
60
+ *
61
+ * A cell whose outcome is a distribution, for example under netem loss, has no band. Its
62
+ * prediction is `detects: null` with the reason, and its runs are measurements only.
63
+ */
64
+ type Prediction = {
65
+ readonly detects: true;
66
+ /** This name is the timer of the machine that fires first, or the event that detects the fault, with its errno. */
67
+ readonly timer: string;
68
+ /** This name is the errno of the detection, or EOF for an end of file without an error. */
69
+ readonly errno: string;
70
+ readonly from: Reference;
71
+ /** This time is the closed form, less the most that the timer can fire early. */
72
+ readonly low: Quantity;
73
+ /** This time is the closed form, plus the most that the timer can fire late. */
74
+ readonly high: Quantity;
75
+ } | {
76
+ readonly detects: false;
77
+ readonly window: Quantity;
78
+ readonly recovers?: Recovers;
79
+ } | {
80
+ readonly detects: null;
81
+ readonly window: Quantity;
82
+ readonly why: string;
83
+ };
84
+ /** A target is the server that a cell connects to: a stock image. */
85
+ interface Target {
86
+ /** This image is a stock image, pinned by digest. */
87
+ readonly image: string;
88
+ readonly port: number;
89
+ /** This text is the log line that tells that the target serves. */
90
+ readonly ready: string;
91
+ /**
92
+ * These commands set and read one setting of the target, as argv in it. The name and the value
93
+ * come after them: `redis-cli CONFIG SET` and `CONFIG GET` for Redis. Without them, the target
94
+ * has no settings to set.
95
+ */
96
+ readonly settings?: {
97
+ readonly set: readonly string[];
98
+ readonly get: readonly string[];
99
+ };
100
+ /**
101
+ * This command replaces the command of the image, for example a shell that holds the server
102
+ * process as its child. Then a `fin` fault can stop the server, and the container stays up.
103
+ */
104
+ readonly command?: readonly string[];
105
+ /** This command stops the server process in the target with SIGKILL, as argv, for a `fin` fault. */
106
+ readonly kill?: readonly string[];
107
+ }
108
+ /** A client is what the runs of a cell use: the TCP client of the harness, or a driver on its socket. */
109
+ type Client = "tcp" | "ioredis";
110
+ /**
111
+ * An observer is the side whose detection a cell measures. The client is one observer. The
112
+ * server is the other observer. It is the hold of the target on the connection of the client, at
113
+ * its server socket in its namespace. The fault is on the peer of the observer. Thus
114
+ * freeze-process freezes the target for the client, and the client for the server.
115
+ */
116
+ type Observer = "client" | "server";
117
+ /** A cell is one cell of the matrix: a topology, its settings, a workload, a fault and the prediction. */
118
+ interface Cell {
119
+ readonly name: string;
120
+ readonly target: Target;
121
+ /** These are the sysctls of the network namespace of the client, as the kernel spells them. The harness sets them before the client connects. */
122
+ readonly sysctls: Readonly<Record<string, string>>;
123
+ readonly probe: {
124
+ /**
125
+ * This mode tells if the client is idle after its first reply, or sends a request into the
126
+ * fault. In a stream, it sends `count` requests into it, each `interval` after the reply before.
127
+ */
128
+ readonly mode: "idle" | "inflight" | "stream";
129
+ /** This count is the number of requests of a stream. */
130
+ readonly count?: number;
131
+ /** This time is the pause after each reply of a stream, before the next request. */
132
+ readonly interval?: Quantity;
133
+ /** This flag sets SO_KEEPALIVE without overrides for the socket: the keepalive sysctls of the namespace apply. */
134
+ readonly keepalive: boolean;
135
+ /** This time sets TCP_USER_TIMEOUT. Without it, the default of the kernel (off) applies. */
136
+ readonly userTimeout?: Quantity;
137
+ /**
138
+ * This text is the request that an in-flight run sends, as a Redis inline command. Without it,
139
+ * the request is PING. BLPOP with a timeout makes the server answer only at the timeout. Thus
140
+ * a cell on the server side has a reply in flight when the fault occurs.
141
+ */
142
+ readonly request?: string;
143
+ /**
144
+ * This driver replaces the TCP client of the harness, with its own options. It is ioredis 6 on
145
+ * Node, whose keepAlive is the keepalive delay of the socket. The driver then ignores `keepalive`
146
+ * and `userTimeout`.
147
+ */
148
+ readonly driver?: {
149
+ readonly name: "ioredis";
150
+ readonly keepAlive: Quantity;
151
+ };
152
+ };
153
+ readonly fault: Fault;
154
+ /** This time is the length of a stall, from the send of the request. */
155
+ readonly stall?: Quantity;
156
+ /** This code is the ICMP unreachable of an `unreachable` fault. */
157
+ readonly icmp?: "host" | "net" | "port" | "admin";
158
+ /** This direction is the one that a `simplex` fault drops: the segments to the server, or to the client. */
159
+ readonly drops?: "to-server" | "to-client";
160
+ /** This length is the longest segment, in bytes, that an `mtu-blackhole` fault lets through to the observer. */
161
+ readonly mtu?: number;
162
+ /** This specification is the tc netem of a `netem` fault, on the egress of the target: for example "loss 5%". */
163
+ readonly netem?: string;
164
+ /**
165
+ * This delay goes on the egress of the target before the client connects, with tc netem. Thus
166
+ * each round trip is longer by the delay, and so is the RTO.
167
+ */
168
+ readonly latency?: Quantity;
169
+ /** These commands run in the target before a client connects, each as argv: for example, a large value to read. */
170
+ readonly targetSetup?: readonly (readonly string[])[];
171
+ readonly prediction: Prediction;
172
+ /** This side is the side whose detection the cell measures. Without it, the side is the client. */
173
+ readonly observer?: Observer;
174
+ /** These are the settings of the target. The harness sets them in each environment before a client connects. */
175
+ readonly targetSettings?: Readonly<Record<string, string>>;
176
+ /** These are the sysctls of the network namespace of the target, for a cell on the server side: its tcp_retries2. */
177
+ readonly targetSysctls?: Readonly<Record<string, string>>;
178
+ /** This count is the number of runs of the cell (11), across new environments (two at least). */
179
+ readonly runs: number;
180
+ readonly environments: number;
181
+ /**
182
+ * This count is the number of environments at the same time, each with its own prober. Without
183
+ * it, the count is one. The calibration does its reference cells at 1, 4 and 8, to find how
184
+ * many environments the machine holds before its noise increases.
185
+ */
186
+ readonly concurrency?: number;
187
+ }
188
+ /** A probe event is one line that the client wrote. `t` is CLOCK_MONOTONIC in nanoseconds: an instant, not an amount. */
189
+ interface ProbeEvent {
190
+ readonly ev: string;
191
+ readonly t: number;
192
+ readonly [field: string]: unknown;
193
+ }
194
+ /** A run is one run of a cell, as the harness records it. */
195
+ interface Run {
196
+ readonly environment: number;
197
+ readonly index: number;
198
+ readonly events: readonly ProbeEvent[];
199
+ /** This bracket is the time of the injector around the commit of the fault, on the same clock. It is null for a freeze. */
200
+ readonly fault: {
201
+ readonly t0: number;
202
+ readonly t1: number;
203
+ } | null;
204
+ /** This bracket is the time around the commit that stopped a stall. */
205
+ readonly heal?: {
206
+ readonly t0: number;
207
+ readonly t1: number;
208
+ } | null;
209
+ /** These are the records of the prober from the start to the end of the run, in the two namespaces. */
210
+ readonly kernel: readonly KernelRecord[];
211
+ /** This inode identifies the network namespace of the client, thus the records of the client. */
212
+ readonly netns: number;
213
+ /** This inode identifies the namespace of the target, where the records of its server socket are. */
214
+ readonly targetNetns: number;
215
+ /**
216
+ * This count is the number of records that the prober lost in the run. One lost record makes
217
+ * the run void. Null also makes the run void: no clock line came after the run to tell the count.
218
+ */
219
+ readonly lost: number | null;
220
+ }
221
+ //#endregion
222
+ //#region src/observe.d.ts
223
+ /**
224
+ * An outcome tells how the wait of a run ended. The socket failed with an errno, or it read the
225
+ * end of the file. Or nothing came, or the reply came back after a stall.
226
+ */
227
+ type Outcome = {
228
+ readonly kind: "error";
229
+ readonly errno: string;
230
+ } | {
231
+ readonly kind: "eof";
232
+ } | {
233
+ readonly kind: "silent";
234
+ } | {
235
+ readonly kind: "answered";
236
+ };
237
+ /** A measurement is what one run measured, against the prediction of its cell. */
238
+ interface Measured {
239
+ readonly environment: number;
240
+ readonly index: number;
241
+ readonly outcome: Outcome;
242
+ /**
243
+ * This time is from the reference event of the prediction to the detection, both as the kernel
244
+ * stamped them in the records of the prober. It is null when nothing detected the fault.
245
+ */
246
+ readonly elapsed: Quantity | null;
247
+ /** This time is the same interval from the TCP_INFO samples of the client, the second vantage. */
248
+ readonly socket: Quantity | null;
249
+ /** This time is how long the client took to see the error after the kernel reported it. */
250
+ readonly noticed: Quantity | null;
251
+ /**
252
+ * These are the steps of the kernel after the reference: each keepalive probe, or each firing of
253
+ * the RTO timer. After a stall, they are each retransmission from the send, the loss probe first.
254
+ */
255
+ readonly steps: readonly Quantity[];
256
+ /**
257
+ * These are the reply times of a measurement-only cell. For each request after the first, a
258
+ * sample is the time from its send to the first data after it.
259
+ */
260
+ readonly samples?: readonly Quantity[];
261
+ /** This count is the number of keepalive probes that the kernel sent. */
262
+ readonly probes: number;
263
+ /** This count is the number of segments that the kernel sent again. */
264
+ readonly retransmissions: number;
265
+ /** This count is the number of segments that the socket received after the request. */
266
+ readonly acks: number;
267
+ /** This text is the reason that the run cannot count, or null. A void run is not a pass and not a finding. */
268
+ readonly void: string | null;
269
+ /** This text tells what in the run disagrees with the prediction, other than its timing, or null. */
270
+ readonly finding: string | null;
271
+ }
272
+ /**
273
+ * This function reads one run against its cell, from the records of the kernel first.
274
+ * - The socket of the run is the socket that the client connected from, in its namespace.
275
+ * - The fault must hold before the event that it must meet. That is before the request goes into
276
+ * it, and before the first keepalive probe. A live peer answers that probe, and the answer
277
+ * starts the idle time again. A run where the fault was late is void. A run whose records the
278
+ * prober lost is also void.
279
+ */
280
+ export declare const measure: (cell: Cell, run: Run) => Measured;
281
+ //#endregion
282
+ //#region src/verdict.d.ts
283
+ /**
284
+ * This amount is the noise of the pipeline itself, δ_abs, as the calibration measured it. It is
285
+ * the 99.9th percentile of the whole latency of a reset, at the concurrency cap or less. Its
286
+ * minimum is one jiffy. On 2026-10-12 the worst of 60 resets at 1 and 4 environments took
287
+ * 1.141 ms, thus the minimum sets it to 4 ms. The calibration occurs again after each change to
288
+ * the harness, the kernel or Docker.
289
+ */
290
+ export declare const NOISE: Quantity;
291
+ /** This fraction, δ_rel, is how far the median of a cell can be outside the prediction and stay equivalent. */
292
+ export declare const RELATIVE = .05;
293
+ /** These are the run counts of a cell: 11, then 22 and 44 while its median crosses the edge of the band. */
294
+ export declare const STEPS: readonly [11, 22, 44];
295
+ /**
296
+ * A decision is the result of a verdict. A cell whose outcome is a distribution has no band, and
297
+ * its decision is `measured`: a record, not a test.
298
+ */
299
+ type Decision = "holds" | "fails" | "extend" | "inconclusive" | "measured";
300
+ /** An interval is a range of times. */
301
+ interface Interval {
302
+ readonly low: Quantity;
303
+ readonly high: Quantity;
304
+ }
305
+ /** A verdict is the judgement of a cell on its runs. */
306
+ interface Verdict {
307
+ readonly decision: Decision;
308
+ readonly counted: number;
309
+ readonly voided: number;
310
+ /** This band is where each run must land: [T_lo − δ_abs, T_hi + δ_abs]. It is null for a silent prediction. */
311
+ readonly band: Interval | null;
312
+ /** These are the runs outside the band, and the reason for each. Each is a finding. */
313
+ readonly outside: ReadonlyArray<{
314
+ readonly run: string;
315
+ readonly why: string;
316
+ }>;
317
+ readonly median: Quantity | null;
318
+ /** This interval is the order-statistic interval of the median at 95 %, or the whole range for fewer than six runs. */
319
+ readonly medianInterval: Interval | null;
320
+ readonly why: string;
321
+ }
322
+ /**
323
+ * This function gives the distribution-free interval of a median: [x_(k), x_(n+1−k)], for the
324
+ * largest k whose two tails each hold 2.5 % or less. For eleven runs, it gives [x_(2), x_(10)],
325
+ * at 98.8 %.
326
+ */
327
+ export declare const medianInterval: (sorted: readonly number[]) => [number, number];
328
+ /**
329
+ * This function gives the verdict of a cell, from two tests:
330
+ * - Containment: each run lands in [T_lo − δ_abs, T_hi + δ_abs]. A run outside is a finding.
331
+ * - Median equivalence: the interval of the median is in the band, made wider by δ_rel. An
332
+ * interval outside the band fails. An interval across its edge extends the cell to 22 runs, then
333
+ * 44, and then the verdict is inconclusive.
334
+ *
335
+ * A silent prediction holds only if no run detected the fault in its window. After a stall, the
336
+ * return of the reply gets the same test as a detection, by its interval, and a detection is a
337
+ * finding. The distribution test (a DKW band) needs a predicted distribution from a simulator,
338
+ * which does not exist at this time.
339
+ */
340
+ export declare const verdictOf: (prediction: Prediction, runs: readonly Measured[]) => Verdict;
341
+ //#endregion
342
+ //#region src/lab.d.ts
343
+ /** This function gives the image of the harness. */
344
+ export declare const harnessImage: () => Promise<string>;
345
+ /** This function gives the image of the Node client. */
346
+ export declare const nodeClientImage: () => Promise<string>;
347
+ /**
348
+ * A network fault is a fault that the injector applies as a filter rule. It is a black hole (both
349
+ * directions, or one), or a reset on the next segment. It can also be an ICMP unreachable for each
350
+ * segment, or a drop of each segment that is longer than a length.
351
+ */
352
+ type NetworkFault = "blackhole" | "rst" | "reject" | "mtu";
353
+ /** These are the options of a network fault: the direction of a black hole, the code of a reject, the length of an MTU drop. */
354
+ interface FaultOptions {
355
+ /** This direction is relative to the namespace of the rule: `in` drops what comes from the peer, `out` what goes to it. */
356
+ readonly direction?: "in" | "out";
357
+ readonly code?: "host" | "net" | "port" | "admin";
358
+ /** This length is the longest segment in bytes that an MTU drop lets through. */
359
+ readonly above?: number;
360
+ }
361
+ /**
362
+ * A fault side is the namespace that gets the rules of a fault: the namespace of the peer of the
363
+ * observer. For the client, it is the namespace of the target (the injector). For the server, it
364
+ * is the namespace of the client (its privileged admin). Rules in the namespace of the observer
365
+ * make its sends fail locally, with EPERM, and the network does not lose them. Thus its
366
+ * retransmissions do not go out. The retransmission tracepoint of the kernel then records none,
367
+ * because it fires only for a retransmission that went out.
368
+ */
369
+ type FaultSide = "target" | "client";
370
+ /** A manifest is what a lab records about its machine, its images and its settings. */
371
+ interface Manifest {
372
+ readonly kernel: string;
373
+ /** This text is the architecture of the machine, as uname -m gives it: x86_64. */
374
+ readonly architecture: string;
375
+ readonly hz: string | null;
376
+ readonly boot_id: string;
377
+ readonly docker: string;
378
+ /** This record is the target, and its settings as it read them back. */
379
+ readonly target: {
380
+ readonly image: string;
381
+ readonly id: string;
382
+ readonly settings: Readonly<Record<string, string>>;
383
+ /** These are the sysctls of its namespace, as read back after the harness set them. */
384
+ readonly sysctls: Readonly<Record<string, string>>;
385
+ };
386
+ readonly harness: {
387
+ readonly image: string;
388
+ readonly id: string;
389
+ readonly packages: string[];
390
+ };
391
+ /** This record is the client of each run: the TCP client of the harness, or a driver from its own image. */
392
+ readonly client: {
393
+ readonly kind: Client;
394
+ readonly image: string;
395
+ };
396
+ /** These are the namespaces that the prober watched, by inode. */
397
+ readonly netns: {
398
+ readonly client: number;
399
+ readonly target: number;
400
+ };
401
+ /** These are the sysctls of the client namespace, as read back after the harness set them. */
402
+ readonly sysctls: Readonly<Record<string, string>>;
403
+ }
404
+ /** A probe is the client container of one run. */
405
+ interface Probe {
406
+ /** This method gives the first event of one of these kinds, or it rejects after `within` ms. */
407
+ until(kinds: readonly string[], within: number): Promise<ProbeEvent>;
408
+ /** This method lets an in-flight probe send its request. */
409
+ go(): Promise<void>;
410
+ /** This method freezes the client with the cgroup freezer: its process stops, and its kernel continues to answer. */
411
+ freeze(): Promise<void>;
412
+ thaw(): Promise<void>;
413
+ /** This method stops the process of the client with SIGKILL. Its kernel then closes its socket with a FIN, or a reset. */
414
+ kill(): Promise<void>;
415
+ readonly events: readonly ProbeEvent[];
416
+ stop(): Promise<void>;
417
+ }
418
+ /** A lab is one environment: the target, the client, the injector and the prober. */
419
+ interface Lab {
420
+ readonly targetIp: string;
421
+ readonly clientIp: string;
422
+ readonly netns: {
423
+ readonly client: number;
424
+ readonly target: number;
425
+ };
426
+ /** These are all the records that the prober wrote, in sequence. */
427
+ readonly kernel: readonly KernelRecord[];
428
+ /** This method sets the sysctls of the client namespace through its privileged sidecar, and reads them back. */
429
+ sysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;
430
+ /** This method sets the settings of the target in it before a client connects, and reads them back. */
431
+ configure(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;
432
+ /** This method sets the sysctls of the target namespace through a privileged sidecar there, and reads them back. */
433
+ targetSysctl(values: Readonly<Record<string, string>>): Promise<Record<string, string>>;
434
+ /**
435
+ * This method applies a fault between the client and the target, from the namespace of the
436
+ * target. The fault is a black hole, or a reset that answers the next segment of the client. The stamps of
437
+ * the injector bracket it.
438
+ */
439
+ fault(kind: NetworkFault, at?: FaultSide, options?: FaultOptions): Promise<{
440
+ t0: number;
441
+ t1: number;
442
+ }>;
443
+ /** This method removes a fault. */
444
+ lift(kind: NetworkFault, at?: FaultSide, options?: FaultOptions): Promise<void>;
445
+ /**
446
+ * This method puts tc netem on the egress of a namespace, for example "delay 20ms" or "loss 5%",
447
+ * or removes it with null. The stamps of the injector bracket it.
448
+ */
449
+ netem(spec: string | null, at?: FaultSide): Promise<{
450
+ t0: number;
451
+ t1: number;
452
+ }>;
453
+ /**
454
+ * This method sets the TSO, GSO and GRO of a namespace. With them off, netem and a length match
455
+ * act on segments, not on GSO super-packets of up to 64 KB.
456
+ */
457
+ offload(on: boolean, at?: FaultSide): Promise<void>;
458
+ /** This method stops the server process in the target with SIGKILL, with the command of the target. */
459
+ kill(): Promise<void>;
460
+ /**
461
+ * This method resolves the neighbors of the path in the two directions, with a ping from each
462
+ * namespace. Without it, the first connection of an environment waits for ARP. Under a netem
463
+ * delay, that wait is one more delayed round, and its round trip and RTO are longer.
464
+ */
465
+ warm(): Promise<void>;
466
+ /** This method runs commands in the target before a client connects, each as argv. */
467
+ setup(commands: ReadonlyArray<readonly string[]>): Promise<void>;
468
+ /**
469
+ * This method stops a black hole at an instant on the monotonic clock of the VM. The injector
470
+ * waits for that instant in the VM, thus the length of a stall does not include the latency of
471
+ * a docker exec. Stamps bracket it, as for a fault.
472
+ */
473
+ heal(at: FaultSide, when: number): Promise<{
474
+ t0: number;
475
+ t1: number;
476
+ }>;
477
+ /**
478
+ * This method removes what the two kernels learned from their earlier connections. These are
479
+ * the TCP metrics that each kernel keeps for a peer address when a connection closes. These metrics set the
480
+ * first round trip of the next connection, and thus its RTO. A run with these metrics is not
481
+ * independent of the run before it.
482
+ */
483
+ forget(): Promise<void>;
484
+ /** This method freezes the target with the cgroup freezer: its process stops, and its kernel continues to answer. */
485
+ freeze(): Promise<void>;
486
+ thaw(): Promise<void>;
487
+ probe(args: readonly string[]): Promise<Probe>;
488
+ /**
489
+ * This method waits for the next clock line of the prober, which gives the count of lost
490
+ * records. It gives null when no clock line comes in 5 s, because then nothing tells the count.
491
+ */
492
+ settle(): Promise<number | null>;
493
+ manifest(sysctls: Readonly<Record<string, string>>, settings?: Readonly<Record<string, string>>, targetSysctls?: Readonly<Record<string, string>>): Promise<Manifest>;
494
+ close(): Promise<void>;
495
+ }
496
+ /**
497
+ * This function opens one environment:
498
+ * - a new network and the stock target.
499
+ * - a client that holds its own network namespace, with a privileged sidecar in it for its
500
+ * sysctls. Docker Desktop keeps /proc/sys read-only in a container that operates.
501
+ * - an injector sidecar in the namespace of the target.
502
+ * - the prober, a privileged container that loads the kernel program and watches the two
503
+ * namespaces.
504
+ *
505
+ * The client of each run is its own container in the namespace of the client. It is the TCP
506
+ * client of the harness, or a driver from its own image (ioredis on Node). The two print the same
507
+ * lines.
508
+ */
509
+ export declare const openLab: (target: Target, kind?: Client) => Promise<Lab>;
510
+ //#endregion
511
+ //#region src/run.d.ts
512
+ /** A cell result is a cell with its manifests, its runs, their measurements and its verdict. */
513
+ interface CellResult {
514
+ readonly cell: Cell;
515
+ readonly manifests: readonly Manifest[];
516
+ readonly runs: readonly Run[];
517
+ readonly measured: readonly Measured[];
518
+ readonly verdict: Verdict;
519
+ /** These times are when its first environment opened and its last environment closed, on the wall clock. */
520
+ readonly at: {
521
+ readonly started: string;
522
+ readonly ended: string;
523
+ };
524
+ }
525
+ /**
526
+ * This function measures and judges the raw records of a cell, with the code of the harness at
527
+ * this time. `runCell` uses it during a cell. A holder of the raw records of a cell can use it
528
+ * again later. Thus the records get a new analysis after a change to observe.ts or to the verdict.
529
+ */
530
+ export declare const judge: (cell: Cell, runs: readonly Run[]) => {
531
+ measured: Measured[];
532
+ verdict: Verdict;
533
+ };
534
+ /** This function divides a count of runs across environments, as equally as possible. */
535
+ export declare const spread: (runs: number, environments: number) => number[];
536
+ /**
537
+ * This function does the runs of a cell. They go across new environments, and each environment records
538
+ * its manifest. Then the verdict judges the runs. A median across the edge of the band extends
539
+ * the cell from 11 runs to 22, and then to 44, each extension in new environments. With a
540
+ * concurrency of more than one, that many environments operate at the same time, each with its
541
+ * own prober. The runs then go across at least as many environments.
542
+ */
543
+ export declare const runCell: (cell: Cell, say?: (line: string) => void) => Promise<CellResult>;
544
+ //#endregion
545
+ export type { Cell, CellResult, Client, Decision, Fault, FaultSide, Interval, KernelRecord, Lab, Manifest, Measured, NetworkFault, Observer, Outcome, Prediction, Probe, ProbeEvent, Recovers, Reference, Run, Target, Verdict };
546
+ //# sourceMappingURL=index.d.ts.map