@mark1russell7/kind 0.0.0-stage → 0.1.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.
@@ -0,0 +1,695 @@
1
+ import { Extent, Quantity } from "@mark1russell7/quantity";
2
+ import { z } from "zod";
3
+ import { Coupling, Gate, Poll, Stage, Timing } from "@mark1russell7/service";
4
+ import { RedisKnobs } from "@mark1russell7/service/redis";
5
+ //#region src/scenario.d.ts
6
+ /** A kube-proxy mode is the dataplane of each node: iptables (the default of kind), IPVS or nftables. */
7
+ type KubeProxyMode = "iptables" | "ipvs" | "nftables";
8
+ declare const KUBE_PROXY_MODES: readonly KubeProxyMode[];
9
+ /** A node image is the kind node image of one Kubernetes version, pinned by digest. */
10
+ interface NodeImage {
11
+ readonly kubernetes: string;
12
+ readonly image: string;
13
+ }
14
+ /**
15
+ * These are the node images of kind v0.33.0, from its release notes. The image of Kubernetes 1.37
16
+ * is v1.37.0. The research names v1.37.1 for some defaults, thus a default that changed in the
17
+ * patch release is a mismatch to record.
18
+ */
19
+ declare const NODE_IMAGES: Readonly<Record<string, NodeImage>>;
20
+ /**
21
+ * A scenario is one kind cluster as data. The lab generates the configuration of kind from it, and
22
+ * nothing comes from a default of kind. The scenario gives the node count, the version, the mode
23
+ * of kube-proxy and its sync periods, the CNI and the subnets.
24
+ */
25
+ interface KindScenario {
26
+ /** This name names the cluster and its Docker network: lowercase letters, digits and dashes. */
27
+ readonly name: string;
28
+ /** This key selects the node image (`NODE_IMAGES`). */
29
+ readonly kubernetes: string;
30
+ /** This count is the number of workers. The cluster also has one control plane. */
31
+ readonly workers: number;
32
+ readonly kubeProxy: {
33
+ readonly mode: KubeProxyMode;
34
+ /** This time is the shortest interval between two syncs of the rules. */
35
+ readonly minSyncPeriod: Quantity;
36
+ /** This time is the interval of the full sync of the rules. */
37
+ readonly syncPeriod: Quantity;
38
+ };
39
+ /** This CNI is kindnet, the CNI of kind. Cilium comes later. */
40
+ readonly cni: "kindnet";
41
+ readonly podSubnet: string;
42
+ readonly serviceSubnet: string;
43
+ }
44
+ /** This function gives a scenario with the defaults of Kubernetes for kube-proxy, as explicit values. */
45
+ declare const scenario: (name: string, mode: KubeProxyMode, workers: number, kubernetes?: string) => KindScenario;
46
+ /** This function gives the problems of a scenario: a name that kind refuses, no image for the version, or a count out of range. */
47
+ declare const scenarioProblems: (s: KindScenario) => string[];
48
+ /** This function gives the names of the node containers, as kind names them: the control plane, then each worker. */
49
+ declare const nodeNames: (s: KindScenario) => string[];
50
+ /** This function gives a duration as kube-proxy reads it, in whole milliseconds: `1s`, `500ms`. */
51
+ declare const goDuration: (amount: Quantity) => string;
52
+ /** This function gives the KubeProxyConfiguration patch of a scenario, as kubeadm reads it. */
53
+ declare const kubeProxyPatch: (s: KindScenario) => string;
54
+ /** A kind configuration is the cluster file that `kind create cluster --config` reads. JSON is YAML, thus the lab writes it as JSON. */
55
+ interface KindConfig {
56
+ readonly kind: "Cluster";
57
+ readonly apiVersion: "kind.x-k8s.io/v1alpha4";
58
+ readonly networking: {
59
+ readonly ipFamily: "ipv4";
60
+ readonly kubeProxyMode: KubeProxyMode;
61
+ readonly disableDefaultCNI: boolean;
62
+ readonly podSubnet: string;
63
+ readonly serviceSubnet: string;
64
+ };
65
+ readonly nodes: ReadonlyArray<{
66
+ readonly role: "control-plane" | "worker";
67
+ readonly image: string;
68
+ readonly labels: Readonly<Record<string, string>>;
69
+ }>;
70
+ readonly kubeadmConfigPatches: readonly string[];
71
+ }
72
+ /** This function generates the configuration of kind from a scenario. It refuses a scenario with a problem. */
73
+ declare const kindConfig: (s: KindScenario) => KindConfig;
74
+ /** This function gives the first and the last address of an IPv4 CIDR, as numbers. */
75
+ declare const cidrRange: (cidr: string) => [number, number];
76
+ /** This function tells if two IPv4 CIDRs share an address. */
77
+ declare const cidrOverlap: (a: string, b: string) => boolean;
78
+ //#endregion
79
+ //#region src/cell.d.ts
80
+ /** A template is the topology of a cell: T07, the endpoint lifecycle of a Service, or T18, a health-gated fleet. */
81
+ type Template = "T07" | "T18";
82
+ /**
83
+ * A trigger is the event or the fault of a cell, by the name of the plan:
84
+ * - `pod-deletion`, `rolling-update`, `node-drain` and `scale-in` stop a pod with its grace.
85
+ * - `crash` stops the process of the service with SIGKILL from the node.
86
+ * - `liveness-restart` fails the liveness check of one replica, and the kubelet restarts it.
87
+ * - `freeze-process` stops a process with SIGSTOP from the node: kube-proxy on one node (T07), or Redis (T18).
88
+ * - `rst` and `blackhole` are the rules of the injector of the harness in the namespace of Redis.
89
+ * - `peer-gone-without-close` drops the segments of Redis, and then Redis goes away.
90
+ * - `app-stall` blocks the event loop of one replica.
91
+ * - `rollout` is a rolling update while Redis is down.
92
+ * - `cpu-throttle` sets `cpu.max` in the cgroup of one replica.
93
+ * - `none` injects nothing: a calibration measures the path itself.
94
+ */
95
+ type TriggerKind = "pod-deletion" | "rolling-update" | "node-drain" | "scale-in" | "crash" | "liveness-restart" | "freeze-process" | "rst" | "blackhole" | "peer-gone-without-close" | "app-stall" | "rollout" | "cpu-throttle";
96
+ /**
97
+ * A trigger is its kind and the settings of its fault. The parameter `A` is the form of an amount:
98
+ * a quantity in the format `/2`, a number in the format `/1`.
99
+ */
100
+ interface Trigger<A = Quantity> {
101
+ readonly kind: TriggerKind;
102
+ /** This time is how long a fault holds before it ends: a stall, a pause of kube-proxy, a black hole on Redis. */
103
+ readonly hold?: Quantity | undefined;
104
+ /** This time is how long before the deletion a pause of kube-proxy starts (T07 `freeze-process`). */
105
+ readonly lead?: Quantity | undefined;
106
+ /** This value is the `cpu.max` of a throttle: the quota and the period. The format `/1` gives each one in microseconds. */
107
+ readonly cpuMax?: {
108
+ readonly quota: A;
109
+ readonly period: A;
110
+ } | undefined;
111
+ }
112
+ /** A kubelet probe is the period, the failure threshold and the timeout of one probe of the pod. */
113
+ interface KubeletProbe {
114
+ readonly period: Quantity;
115
+ readonly threshold: number;
116
+ readonly timeout: Quantity;
117
+ }
118
+ /** The pod settings are the part of the cell that the manifest of the Deployment holds. */
119
+ interface PodSettings {
120
+ readonly replicas: number;
121
+ /** This time is `terminationGracePeriodSeconds`. */
122
+ readonly grace: Quantity;
123
+ /** This time is the preStop sleep, or zero for no preStop hook. */
124
+ readonly preStop: Quantity;
125
+ readonly readiness: KubeletProbe;
126
+ readonly liveness: KubeletProbe;
127
+ /** This probe is the startup probe, or null for none, the default of Kubernetes. */
128
+ readonly startup: KubeletProbe | null;
129
+ }
130
+ /** The Redis part of a declaration: the gate of the round trip of the client, its knobs and its watchdog. */
131
+ interface RedisDeclaration {
132
+ /** This gate is the policy that the round-trip check controls, or null for a check that only reports. */
133
+ readonly gates: Gate | null;
134
+ readonly knobs: RedisKnobs;
135
+ readonly misses: number;
136
+ }
137
+ /**
138
+ * A declaration is the settings of the service in the image. The app composes its service from them
139
+ * with `@mark1russell7/service`, and `lint()` reads the same declaration.
140
+ */
141
+ interface Declaration {
142
+ readonly poll: Poll;
143
+ readonly readiness: Timing;
144
+ readonly liveness: Timing;
145
+ readonly startup: Quantity;
146
+ /** These are the caps of each stage of the shutdown, in the sequence of the stages. */
147
+ readonly phases: ReadonlyArray<readonly [Stage, Quantity]>;
148
+ readonly cooperativeWindow: Extent;
149
+ readonly couplings: readonly Coupling[];
150
+ /** This part is null for a service without Redis. */
151
+ readonly redis: RedisDeclaration | null;
152
+ /** This gate is the policy of the check that a flag file fails, the seam of `liveness-restart`, or null for no such check. */
153
+ readonly flag: Gate | null;
154
+ /** This watchdog of the event loop gates liveness: a tick later than the threshold fails it. Null declares no watchdog. */
155
+ readonly watchdog: {
156
+ readonly tick: Quantity;
157
+ readonly threshold: Quantity;
158
+ } | null;
159
+ }
160
+ /** A workload is the clients: one pod on each node, each with requests on new connections to the ClusterIP. */
161
+ interface Workload {
162
+ /** This time is the interval between two requests of one client. The clients do not wait for an answer. */
163
+ readonly every: Quantity;
164
+ /** This time is how long a client waits for an answer before the request is a timeout. */
165
+ readonly timeout: Quantity;
166
+ }
167
+ /**
168
+ * A band is a range of times after a reference event of the run. The format `/1` gives each end
169
+ * in seconds, as a number.
170
+ */
171
+ interface Band<A = Quantity> {
172
+ readonly lo: A;
173
+ readonly hi: A;
174
+ }
175
+ /**
176
+ * A reference is the event of a run that a band counts from:
177
+ * - `deletion`: the first deletion timestamp of a target pod, as the watcher receives it.
178
+ * - `intake`: the stop of the intake of the target pod, as its service records it.
179
+ * - `fault`: the commit of the fault, as the injector or the agent stamps it.
180
+ * - `resume`: the end of a pause of kube-proxy, as the agent stamps it.
181
+ */
182
+ type Reference = "deletion" | "intake" | "fault" | "resume";
183
+ /**
184
+ * A prediction is what the cell expects:
185
+ * - `none`: no request fails in the run.
186
+ * - `window`: the requests that fail start in a window. The window starts at `start` and ends in
187
+ * `end`. With `certain`, at least one request fails.
188
+ * - `removal`: the Service has no ready endpoint, and the rules of each node have no backend, in the band.
189
+ * - `leaves`: the target replica leaves the EndpointSlice and the rules of each node in the band.
190
+ * - `restarts`: each replica receives SIGTERM in the band, or no replica does.
191
+ * - `stays`: no endpoint leaves the Service, and no request is refused.
192
+ * - `stalls`: the rollout does not continue while Redis is down, and it ends after Redis is back.
193
+ * - `measured`: no document bounds the outcome. The run keeps the measurement.
194
+ */
195
+ type Prediction<A = Quantity> = {
196
+ readonly kind: "none";
197
+ /** These outcomes are the failures that the prediction excludes. Without them, it excludes each outcome but `ok`. */
198
+ readonly outcomes?: readonly string[] | undefined;
199
+ readonly why: string;
200
+ } | {
201
+ readonly kind: "window";
202
+ readonly nodes: "all" | "paused";
203
+ readonly start: {
204
+ readonly from: Reference;
205
+ readonly band: Band<A>;
206
+ };
207
+ readonly end: {
208
+ readonly from: Reference;
209
+ readonly band: Band<A>;
210
+ } | null;
211
+ readonly certain: boolean;
212
+ readonly why: string;
213
+ } | {
214
+ readonly kind: "removal";
215
+ readonly band: Band<A>;
216
+ readonly why: string;
217
+ } | {
218
+ readonly kind: "leaves";
219
+ readonly band: Band<A>;
220
+ readonly why: string;
221
+ } | {
222
+ readonly kind: "restarts";
223
+ readonly band: Band<A> | null;
224
+ readonly why: string;
225
+ } | {
226
+ readonly kind: "stays";
227
+ readonly why: string;
228
+ } | {
229
+ readonly kind: "stalls";
230
+ readonly why: string;
231
+ } | {
232
+ readonly kind: "measured";
233
+ readonly why: string;
234
+ };
235
+ /** A replica is one pod of the service at the start of a run. */
236
+ interface Replica {
237
+ readonly pod: string;
238
+ readonly node: string;
239
+ readonly ip: string;
240
+ readonly version: string;
241
+ }
242
+ /**
243
+ * A kind run is one run of a cell: its lines, the stamps of its acts, and the replicas at its
244
+ * start. The judge derives each other reference from the lines, thus a holder of the raw record
245
+ * can judge it again.
246
+ *
247
+ * A stamp is a reading of CLOCK_MONOTONIC in milliseconds. It is a point on a clock, not an
248
+ * amount, thus it stays a number, as in each line.
249
+ */
250
+ interface KindRun {
251
+ readonly env: number;
252
+ readonly index: number;
253
+ readonly warmup: boolean;
254
+ /** These stamps are the start and the end of the run. */
255
+ readonly start: number;
256
+ readonly end: number;
257
+ /** These are the stamps of the acts: the start of the fault, its heal, and the end of a pause of kube-proxy. */
258
+ readonly acts: {
259
+ readonly fault: number | null;
260
+ readonly heal: number | null;
261
+ readonly resume: number | null;
262
+ };
263
+ /** This replica is the target of the trigger, or null for a fault on Redis. */
264
+ readonly target: Replica | null;
265
+ /** This node is the node whose kube-proxy paused, or null. */
266
+ readonly paused: string | null;
267
+ readonly replicas: readonly Replica[];
268
+ readonly void: string | null;
269
+ readonly lines: ReadonlyArray<{
270
+ readonly ev: string;
271
+ readonly t: number;
272
+ readonly [field: string]: unknown;
273
+ }>;
274
+ /** These counts are the kernel records that the lab did not keep, by kind. */
275
+ readonly dropped: Readonly<Record<string, number>>;
276
+ /** These texts tell of an act of the heal or the restore that failed. */
277
+ readonly notes?: readonly string[] | undefined;
278
+ }
279
+ /** A kind cell is all that one measurement in kind needs, as data. The parameter `A` is the form of an amount. */
280
+ interface KindCell<A = Quantity> {
281
+ /** This identifier is the cell of the plan that the cell stands for. */
282
+ readonly id: string;
283
+ readonly name: string;
284
+ readonly template: Template;
285
+ /** This text names a system of the plan that the cell replaces with the service of this repository, or null. */
286
+ readonly substitutes: string | null;
287
+ readonly mode: KubeProxyMode;
288
+ readonly workers: number;
289
+ readonly trigger: Trigger<A>;
290
+ readonly pod: PodSettings;
291
+ readonly declaration: Declaration;
292
+ readonly workload: Workload;
293
+ readonly prediction: Prediction<A>;
294
+ /** This flag marks a calibration: its runs measure the propagation of the endpoints, and nothing fails. */
295
+ readonly calibrates: boolean;
296
+ readonly runs: number;
297
+ }
298
+ //#endregion
299
+ //#region src/bands.d.ts
300
+ /** This module makes and prints the bands of the predictions. It imports only the amounts. */
301
+ /** This function gives a time in seconds as a quantity. */
302
+ declare const seconds: (value: number) => Quantity;
303
+ /** This function gives a band from its two ends in seconds. */
304
+ declare const bandOf: (lo: number, hi: number) => Band;
305
+ /** This function gives the two ends of a band as numbers of seconds, for arithmetic. */
306
+ declare const secondsOf: (band: Band) => {
307
+ readonly lo: number;
308
+ readonly hi: number;
309
+ };
310
+ /** This function gives a band in a short form for a name or a table: `[28, 49] s`. */
311
+ declare const showBand: (band: Band) => string;
312
+ //#endregion
313
+ //#region src/names.d.ts
314
+ /** These are the ports of the app: its server, and its health server for the probes. */
315
+ declare const PORT = 8080;
316
+ declare const HEALTH_PORT = 9e3;
317
+ /** This label makes the watcher follow the log of a pod. */
318
+ declare const LOG_LABEL = "lab.systems/log";
319
+ /** These are the names of the objects of a cell. */
320
+ declare const SERVER = "lab";
321
+ declare const CLIENT = "client";
322
+ declare const REDIS = "redis";
323
+ //#endregion
324
+ //#region src/observe.d.ts
325
+ /**
326
+ * This module reads a run from its lines. Each time is in milliseconds on CLOCK_MONOTONIC. All the
327
+ * containers of the VM share that clock: the clients, the service, the agents, the injector, the
328
+ * watcher and the prober.
329
+ */
330
+ /**
331
+ * A line is one JSON line of a source of a run, with its stamp `t` in milliseconds on
332
+ * CLOCK_MONOTONIC. It is a request of a client, a record of the service or a probe answer. It is
333
+ * also a pod, an EndpointSlice or an event of the API. Or it is the backends of the rules of a
334
+ * node, a kernel record, or an act of the lab. A record keeps each line as its source wrote it.
335
+ */
336
+ interface Line {
337
+ readonly ev: string;
338
+ readonly t: number;
339
+ readonly [field: string]: unknown;
340
+ }
341
+ /** A request is one request of a client: its start, its duration in ms, its outcome, its client and the node of the client. */
342
+ interface Request {
343
+ readonly t: number;
344
+ readonly d: number;
345
+ readonly o: string;
346
+ readonly p: string;
347
+ readonly n: string;
348
+ readonly b?: string;
349
+ }
350
+ /** A pod line is one state of a pod, as the watcher received it. */
351
+ interface PodLine {
352
+ readonly t: number;
353
+ readonly type: string;
354
+ readonly name: string;
355
+ readonly node: string | null;
356
+ readonly ip: string | null;
357
+ readonly del: boolean;
358
+ readonly ready: boolean;
359
+ readonly phase: string | null;
360
+ readonly cs: ReadonlyArray<{
361
+ readonly n: string;
362
+ readonly r: boolean;
363
+ readonly rc: number;
364
+ readonly st: string;
365
+ readonly id: string | null;
366
+ }>;
367
+ readonly labels: Readonly<Record<string, string>>;
368
+ }
369
+ /** An endpoint is one endpoint of an EndpointSlice: its address, its conditions and its pod. */
370
+ interface Endpoint {
371
+ readonly ip: string | null;
372
+ readonly r: boolean | null;
373
+ readonly s: boolean | null;
374
+ readonly x: boolean | null;
375
+ readonly pod: string | null;
376
+ readonly node: string | null;
377
+ }
378
+ /** A slice line is one state of an EndpointSlice. */
379
+ interface SliceLine {
380
+ readonly t: number;
381
+ readonly type: string;
382
+ readonly name: string;
383
+ readonly svc: string | null;
384
+ readonly eps: readonly Endpoint[];
385
+ }
386
+ /** A rules line is the backends of the Service in the rules of one node, after a change. `prev` is the start of the poll before it. */
387
+ interface RulesLine {
388
+ readonly t: number;
389
+ readonly prev: number | null;
390
+ readonly node: string;
391
+ readonly b: readonly string[];
392
+ }
393
+ /** A record line is one transition of a machine of the service, with its own stamp `at`. */
394
+ interface RecordLine {
395
+ readonly t: number;
396
+ readonly at: number;
397
+ readonly p: string;
398
+ readonly m: string;
399
+ readonly i: string;
400
+ readonly from: string;
401
+ readonly to: string;
402
+ readonly on: string;
403
+ readonly d: string | null;
404
+ }
405
+ declare const requestsOf: (lines: readonly Line[]) => Request[];
406
+ declare const podsOf: (lines: readonly Line[]) => PodLine[];
407
+ declare const slicesOf: (lines: readonly Line[], svc: string) => SliceLine[];
408
+ declare const rulesOf: (lines: readonly Line[]) => RulesLine[];
409
+ declare const recordsOf: (lines: readonly Line[]) => RecordLine[];
410
+ /** This function gives the requests that did not succeed, in sequence of their start. */
411
+ declare const failuresOf: (lines: readonly Line[]) => Request[];
412
+ /** This function counts the outcomes of the requests, by outcome. */
413
+ declare const outcomesOf: (requests: readonly Request[]) => Record<string, number>;
414
+ /** This function gives the requests of each node, by the name of the node. */
415
+ declare const byNode: (requests: readonly Request[]) => Map<string, Request[]>;
416
+ /** This function gives the time that the watcher first received a deletion timestamp of one of the pods, after a time. */
417
+ declare const deletionOf: (lines: readonly Line[], pods: readonly string[], after: number) => number | null;
418
+ /** This function gives the stamp of a transition of the service in a pod: the first matching record of a machine, after a time. */
419
+ declare const transitionOf: (lines: readonly Line[], pod: string, machine: string, match: (record: RecordLine) => boolean, after: number) => number | null;
420
+ /** This function gives when the service of a pod stopped its intake: the start of the phase `stop intake`. */
421
+ declare const intakeOf: (lines: readonly Line[], pod: string, after: number) => number | null;
422
+ /** This function gives when the service of a pod received its exit signal. */
423
+ declare const signalOf: (lines: readonly Line[], pod: string, after: number) => number | null;
424
+ /**
425
+ * This function gives when the rules of a node stopped the selection of a backend: the first poll
426
+ * after a time without it. The change came after `prev`, the poll before it, and at the latest at `t`.
427
+ */
428
+ declare const dropOf: (lines: readonly Line[], node: string, backend: string, after: number) => RulesLine | null;
429
+ /** This function gives when the rules of a node had no backend of the Service, after a time. */
430
+ declare const emptyOf: (lines: readonly Line[], node: string, after: number) => RulesLine | null;
431
+ /** This function gives when an EndpointSlice of the Service first had no ready endpoint, after a time. */
432
+ declare const sliceEmptyOf: (lines: readonly Line[], svc: string, after: number) => number | null;
433
+ /** This function gives when the endpoint of an address was first not ready in the EndpointSlice of the Service, after a time. */
434
+ declare const sliceDropOf: (lines: readonly Line[], svc: string, ip: string, after: number) => number | null;
435
+ /** This function gives the latest state of each pod at a time, by its name. A deleted pod is not in it. */
436
+ declare const podsAt: (lines: readonly Line[], at: number) => Map<string, PodLine>;
437
+ /** This function gives the latest backends of each node at a time, by node. */
438
+ declare const backendsAt: (lines: readonly Line[], at: number) => Map<string, readonly string[]>;
439
+ /** This function gives the kernel records of the kinds that the lab keeps, counted by kind. */
440
+ declare const kernelCounts: (lines: readonly Line[]) => Record<string, number>;
441
+ /** This function gives the SIGTERM of each pod in a set after a time, by pod. A pod without one is not in it. */
442
+ declare const signalsOf: (lines: readonly Line[], pods: readonly string[], after: number) => Map<string, number>;
443
+ /** This function gives the restart count of each container of each pod at a time, summed by pod. */
444
+ declare const restartsAt: (lines: readonly Line[], at: number) => Map<string, number>;
445
+ //#endregion
446
+ //#region src/verdict.d.ts
447
+ /**
448
+ * This time is δ for kind: each time of a run lands in its band ± δ. Its parts are the interval of
449
+ * the poll of the rules (50 ms) and the delay of the watcher. The watcher receives each change after
450
+ * the API server writes it.
451
+ */
452
+ declare const KIND_NOISE: Quantity;
453
+ /**
454
+ * This time is how much earlier than the end of its window the last failed request can start. A
455
+ * request goes to the closed pod by the choice of the rules, thus the last ones before the end can
456
+ * go to another pod. At 50 requests a second and two pods, 12 requests in sequence miss the closed
457
+ * pod with a chance of 1 in 4096.
458
+ */
459
+ declare const LAST_SLACK: Quantity;
460
+ /** A propagated change is when the rules of a node first had it: after the poll `after`, and by the poll `by`. */
461
+ interface Propagated<A = Quantity> {
462
+ readonly after: A | null;
463
+ readonly by: A;
464
+ }
465
+ /**
466
+ * The facts of a run are what each table reads: its failures by outcome and node, and the times of
467
+ * its target. A count stays a number, and so does a stamp: `first`, `last` and `deletion` are
468
+ * readings of CLOCK_MONOTONIC in milliseconds. Each other time is an amount after a reference. The
469
+ * parameter `A` is the form of an amount: a quantity in the format `/2`, seconds in the format `/1`.
470
+ */
471
+ interface RunFacts<A = Quantity> {
472
+ readonly failures: number;
473
+ readonly outcomes: Readonly<Record<string, number>>;
474
+ readonly byNode: Readonly<Record<string, number>>;
475
+ readonly first: number | null;
476
+ readonly last: number | null;
477
+ readonly deletion: number | null;
478
+ readonly intakeAfterDeletion: A | null;
479
+ readonly sliceAfter: A | null;
480
+ /** This record is the propagation of the target to the rules of each node, by node. */
481
+ readonly propagation: Readonly<Record<string, Propagated<A> | null>>;
482
+ /** This time is when the EndpointSlice had no ready endpoint, after the fault (`removal`). */
483
+ readonly sliceEmpty?: A | undefined;
484
+ /** These times are when the rules of each node had no backend, after the fault (`removal`). */
485
+ readonly rules?: Readonly<Record<string, A | null>> | undefined;
486
+ /** This time is when the target left the EndpointSlice, after the fault (`leaves`). */
487
+ readonly left?: A | undefined;
488
+ /** These times are the SIGTERM of each replica, after the fault (`restarts`). */
489
+ readonly signals?: ReadonlyArray<A | null> | undefined;
490
+ }
491
+ /**
492
+ * A run check is the judgement of one run: if it agrees with the prediction, why, its main value,
493
+ * and its facts. The main value is a time, or a count of requests or of replicas (`unitOf`).
494
+ */
495
+ interface RunCheck<A = Quantity> {
496
+ readonly ok: boolean;
497
+ readonly why: string;
498
+ readonly value: A | null;
499
+ readonly facts: RunFacts<A>;
500
+ }
501
+ /** A kind decision is the result of a kind cell. */
502
+ type KindDecision = "holds" | "fails" | "extend" | "measured" | "calibration" | "void";
503
+ /** A kind verdict is the judgement of a cell on its counted runs. */
504
+ interface KindVerdict<A = Quantity> {
505
+ readonly decision: KindDecision;
506
+ readonly counted: number;
507
+ readonly voided: number;
508
+ readonly failed: number;
509
+ /** This amount is the median of the main value of the counted runs, or null. */
510
+ readonly median: A | null;
511
+ readonly why: string;
512
+ readonly checks: ReadonlyArray<RunCheck<A>>;
513
+ }
514
+ /**
515
+ * This function gives the unit of the main value of a cell, from its prediction:
516
+ * - `s` for a time: the removal, the departure or the restart of a band, and the end of a stall.
517
+ * - `{request}` for the failed requests: no failure, a window, a fleet that stays, and a measurement.
518
+ * - `{replica}` for the replicas that received SIGTERM, when no replica must restart.
519
+ */
520
+ declare const unitOf: (prediction: {
521
+ readonly kind: Prediction["kind"];
522
+ readonly band?: unknown;
523
+ }) => string;
524
+ /** This function gives a reference event of a run, as a stamp, or null when the run does not have it. */
525
+ declare const referenceOf: (run: KindRun, from: Reference) => number | null;
526
+ /**
527
+ * This function gives the propagation of each node for the target of a run. It is the time from
528
+ * its deletion (or its crash) to the first poll of the rules of the node without it. The change
529
+ * came between the poll before (`after`) and that poll (`by`).
530
+ */
531
+ declare const propagationOf: (run: KindRun, from: number | null) => Record<string, Propagated | null>;
532
+ /** This function gives the facts of a run that each table reads: its failures by outcome and node, and the times of its target. */
533
+ declare const factsOf: (cell: KindCell, run: KindRun) => RunFacts;
534
+ /** This function judges one run against the prediction of its cell. */
535
+ declare const checkRun: (cell: KindCell, run: KindRun) => RunCheck;
536
+ /** This function judges a cell on its runs: each counted run must agree, and a median in a band must be equivalent to it. */
537
+ declare const judgeKind: (cell: KindCell, runs: readonly KindRun[]) => KindVerdict;
538
+ //#endregion
539
+ //#region src/record.d.ts
540
+ /**
541
+ * This module is the raw record of a kind cell: its formats, and the upgrade from the format `/1`
542
+ * to the format `/2`. The lab writes `/2`, and it does not write `/1` again. A reader reads a record
543
+ * of `/1` through `upgrade`, and the meaning of each value stays the same.
544
+ */
545
+ /** This format is the format that the lab writes. Each amount in it is a quantity. */
546
+ declare const FORMAT = "systems.kind-cell-record/2";
547
+ /** This format is the first format. Its bands, its medians and its times are numbers. */
548
+ declare const FORMAT_V1 = "systems.kind-cell-record/1";
549
+ /** A load sample is what the VM did in 4 s before a run: when (a stamp of the wall clock in milliseconds), its idle share, and its busiest processes. */
550
+ interface LoadSample {
551
+ readonly t: number;
552
+ readonly idle: number;
553
+ readonly top: readonly string[];
554
+ readonly foreign: readonly string[];
555
+ }
556
+ /** A cluster manifest is what a run records about its cluster: the versions, the images, the nodes and the mode as read back. */
557
+ interface ClusterManifest {
558
+ readonly kind: string;
559
+ readonly nodeImage: string;
560
+ readonly server: string;
561
+ readonly mode: string;
562
+ readonly docker: string;
563
+ readonly nodes: ReadonlyArray<{
564
+ readonly name: string;
565
+ readonly kubelet: string;
566
+ readonly kernel: string;
567
+ readonly runtime: string;
568
+ readonly os: string;
569
+ }>;
570
+ }
571
+ /** An environment manifest is one cluster of a cell: its scenario, what the cluster was, and the images of the lab. */
572
+ interface EnvironmentManifest {
573
+ readonly env: number;
574
+ readonly scenario: KindScenario;
575
+ readonly cluster: ClusterManifest;
576
+ readonly images: Readonly<Record<string, string>>;
577
+ }
578
+ /**
579
+ * A kind cell result is a cell, its runs over its environments, the manifest of each environment,
580
+ * and its verdict. The parameter `A` is the form of an amount.
581
+ */
582
+ interface KindCellResult<A = Quantity> {
583
+ readonly cell: KindCell<A>;
584
+ readonly runs: readonly KindRun[];
585
+ readonly manifests: readonly EnvironmentManifest[];
586
+ readonly loads: readonly LoadSample[];
587
+ readonly verdict: KindVerdict<A>;
588
+ /** This text is the time of the verdict, in ISO 8601. */
589
+ readonly at: string;
590
+ }
591
+ /** A kind cell record is the raw record of a cell in the format `/2`: a result with its format. */
592
+ interface KindCellRecord extends KindCellResult {
593
+ readonly format: typeof FORMAT;
594
+ }
595
+ /** A kind cell record of the format `/1` gives each band, median, main value and time of a fact as a number. */
596
+ interface KindCellRecordV1 extends KindCellResult<number> {
597
+ readonly format: typeof FORMAT_V1;
598
+ }
599
+ /** These are the parts of the format `/1`, with numbers for amounts. */
600
+ type BandV1 = Band<number>;
601
+ type PredictionV1 = Prediction<number>;
602
+ type TriggerV1 = Trigger<number>;
603
+ type KindCellV1 = KindCell<number>;
604
+ type KindVerdictV1 = KindVerdict<number>;
605
+ type RunCheckV1 = RunCheck<number>;
606
+ type RunFactsV1 = RunFacts<number>;
607
+ /** This function gives a cell of the format `/1` in the format `/2`: its bands in seconds, and its `cpu.max` in microseconds. */
608
+ declare const upgradeCell: (cell: KindCellV1) => KindCell;
609
+ /**
610
+ * This function gives a record in the format `/2`. A record of `/2` comes back as it is. A record
611
+ * of `/1` gets each amount as a quantity, and each value stays the same:
612
+ * - Each band and each time of a fact is in seconds, as `/1` gives it.
613
+ * - The `cpu.max` of a throttle is in microseconds, as `/1` gives it.
614
+ * - The median and the main value of each run get the unit of the prediction (`unitOf`): seconds,
615
+ * failed requests (`{request}`) or replicas (`{replica}`).
616
+ */
617
+ declare const upgrade: (record: KindCellRecordV1 | KindCellRecord) => KindCellRecord;
618
+ /**
619
+ * This function judges a record again, from its cell and its runs, with the judge of this version.
620
+ * It reads a record of `/1` through `upgrade`. The verdict is in the format `/2`.
621
+ */
622
+ declare const judge: (record: KindCellRecordV1 | KindCellRecord) => KindVerdict;
623
+ //#endregion
624
+ //#region src/report.d.ts
625
+ /** A judged cell is a cell, its runs and its verdict: the part of a result that a report reads. */
626
+ interface Judged {
627
+ readonly cell: KindCell;
628
+ readonly runs: readonly KindRun[];
629
+ readonly verdict: KindVerdict;
630
+ }
631
+ /** A spread is the count, the extremes, the median and the 99th percentile of a set of times. */
632
+ interface TimeSpread {
633
+ readonly count: number;
634
+ readonly min: Quantity;
635
+ readonly median: Quantity;
636
+ readonly p99: Quantity;
637
+ readonly max: Quantity;
638
+ }
639
+ /** This function gives the spread of a set of times, or null for none. The percentile is by nearest rank. */
640
+ declare const timeSpread: (times: readonly Quantity[]) => TimeSpread | null;
641
+ /** This function gives the prediction of a cell in a short form for a table. */
642
+ declare const predictionText: (prediction: Prediction) => string;
643
+ /**
644
+ * This function gives the main measurement of a cell in a short form: its median and what it
645
+ * counts. For failed requests, it is the middle count of the counted runs.
646
+ */
647
+ declare const medianText: (judged: Judged) => string;
648
+ /** This function gives the table of the cells in Markdown. Each row has the cell, its plan cell, its mode, its trigger, the prediction, the verdict, its runs and its median. */
649
+ declare const cellsTable: (judged: readonly Judged[]) => string;
650
+ /**
651
+ * This function gives the propagation of each calibration, by node. It is the time from the
652
+ * deletion to the poll of the rules of each node without the pod. It also gives the time to the
653
+ * EndpointSlice and to the stop of the intake.
654
+ */
655
+ declare const calibrationOf: (judged: Judged) => {
656
+ readonly nodes: Readonly<Record<string, TimeSpread | null>>;
657
+ readonly all: TimeSpread | null;
658
+ readonly slice: TimeSpread | null;
659
+ readonly intake: TimeSpread | null;
660
+ };
661
+ //#endregion
662
+ //#region src/schema.d.ts
663
+ /**
664
+ * This module holds the zod schemas of a kind cell record, in the formats `/1` and `/2`. It names
665
+ * the stages of the shutdown itself, thus it does not load the service. A test holds the names to
666
+ * the service.
667
+ */
668
+ /** These are the stages of the shutdown of the service, in their sequence. */
669
+ declare const STAGES: readonly [Stage, ...Stage[]];
670
+ /**
671
+ * This schema accepts a record in the format `/2`. The median and the main value of each run must
672
+ * have the unit of the prediction of the cell (`unitOf`).
673
+ */
674
+ declare const kindCellRecordSchema: z.ZodType<KindCellRecord>;
675
+ /** This schema accepts a record in the format `/1`. */
676
+ declare const kindCellRecordV1Schema: z.ZodType<KindCellRecordV1>;
677
+ /** This function reads a record of either format from parsed JSON, and gives it in the format `/2`. */
678
+ declare const readRecord: (data: unknown) => KindCellRecord;
679
+ //#endregion
680
+ //#region src/stats.d.ts
681
+ /** This fraction, δ_rel, is how far the median of a cell can be outside its band and stay equivalent. */
682
+ declare const RELATIVE = .05;
683
+ /** This function gives the median of sorted values: the middle value, or the mean of the two middle values. */
684
+ declare const middle: (sorted: readonly number[]) => number;
685
+ /** This function gives the value at quantile p of sorted values, by nearest rank: x_(⌈p·n⌉). */
686
+ declare const quantileOf: (sorted: readonly number[], p: number) => number;
687
+ /**
688
+ * This function gives the distribution-free interval of a median: [x_(k), x_(n+1−k)], for the
689
+ * largest k whose two tails each hold 2.5 % or less. For eleven runs, it gives [x_(2), x_(10)],
690
+ * at 98.8 %.
691
+ */
692
+ declare const medianInterval: (sorted: readonly number[]) => [number, number];
693
+ //#endregion
694
+ export { SliceLine as $, goDuration as $t, TriggerV1 as A, showBand as At, RunFacts as B, Replica as Bt, KindCellResult as C, LOG_LABEL as Ct, PredictionV1 as D, bandOf as Dt, LoadSample as E, SERVER as Et, KindDecision as F, KubeletProbe as Ft, referenceOf as G, KUBE_PROXY_MODES as Gt, factsOf as H, Trigger as Ht, KindVerdict as I, PodSettings as It, Line as J, KubeProxyMode as Jt, unitOf as K, KindConfig as Kt, LAST_SLACK as L, Prediction as Lt, upgrade as M, Declaration as Mt, upgradeCell as N, KindCell as Nt, RunCheckV1 as O, seconds as Ot, KIND_NOISE as P, KindRun as Pt, RulesLine as Q, cidrRange as Qt, Propagated as R, RedisDeclaration as Rt, KindCellRecordV1 as S, HEALTH_PORT as St, KindVerdictV1 as T, REDIS as Tt, judgeKind as U, TriggerKind as Ut, checkRun as V, Template as Vt, propagationOf as W, Workload as Wt, RecordLine as X, NodeImage as Xt, PodLine as Y, NODE_IMAGES as Yt, Request as Z, cidrOverlap as Zt, ClusterManifest as _, sliceDropOf as _t, STAGES as a, failuresOf as at, FORMAT_V1 as b, transitionOf as bt, readRecord as c, outcomesOf as ct, calibrationOf as d, recordsOf as dt, kindConfig as en, backendsAt as et, cellsTable as f, requestsOf as ft, BandV1 as g, signalsOf as gt, timeSpread as h, signalOf as ht, quantileOf as i, scenarioProblems as in, emptyOf as it, judge as j, Band as jt, RunFactsV1 as k, secondsOf as kt, Judged as l, podsAt as lt, predictionText as m, rulesOf as mt, medianInterval as n, nodeNames as nn, deletionOf as nt, kindCellRecordSchema as o, intakeOf as ot, medianText as p, restartsAt as pt, Endpoint as q, KindScenario as qt, middle as r, scenario as rn, dropOf as rt, kindCellRecordV1Schema as s, kernelCounts as st, RELATIVE as t, kubeProxyPatch as tn, byNode as tt, TimeSpread as u, podsOf as ut, EnvironmentManifest as v, sliceEmptyOf as vt, KindCellV1 as w, PORT as wt, KindCellRecord as x, CLIENT as xt, FORMAT as y, slicesOf as yt, RunCheck as z, Reference as zt };
695
+ //# sourceMappingURL=judge-CDDCr1Z8.d.ts.map