@mark1russell7/kind 0.13.0 → 0.13.2

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.
@@ -180,8 +180,11 @@ type Stack = "service" | "grpc";
180
180
  * - `latency` delays each packet that Redis sends by `delay`, for the hold (T07). Thus each command
181
181
  * of each replica takes that much longer, but Redis answers it. The heal sets the delay to zero.
182
182
  * - `none` injects nothing: a calibration measures the path itself.
183
+ * - `dns-blackhole` drops each answer of a DNS server in the network namespace of each client pod,
184
+ * for the hold (S2, CoreDNS). CoreDNS still answers, but no answer gets to a client. The heal
185
+ * removes the rules. A client that resolves the name of the Service (`byName`) sees it.
183
186
  */
184
- 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" | "authorization-policy" | "idle" | "ztunnel-restart" | "certificate-expiry" | "cannot-serve" | "zone-loss" | "latency";
187
+ 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" | "authorization-policy" | "idle" | "ztunnel-restart" | "certificate-expiry" | "cannot-serve" | "zone-loss" | "latency" | "dns-blackhole";
185
188
  /**
186
189
  * A trigger is its kind and the settings of its fault. The parameter `A` is the form of an amount:
187
190
  * a quantity in the format `/2`, a number in the format `/1`.
@@ -366,6 +369,12 @@ interface Workload {
366
369
  * until its first answer comes from its backend. With no value, the rules pick the backend of each session.
367
370
  */
368
371
  readonly onTarget?: number | undefined;
372
+ /**
373
+ * This flag gives each client the name of the Service as its target, not the ClusterIP. Thus each
374
+ * new connection of a client starts with a lookup of the name in the cluster DNS (S2, CoreDNS).
375
+ * With no value, the target is the ClusterIP, and a client does no lookup.
376
+ */
377
+ readonly byName?: boolean | undefined;
369
378
  }
370
379
  /**
371
380
  * A band is a range of times after a reference event of the run. The format `/1` gives each end
@@ -529,6 +538,26 @@ interface WindowPrediction<A = Quantity> {
529
538
  * window has no such term, and the judge does not count the failed requests.
530
539
  */
531
540
  readonly backlog?: BacklogTerm<A> | undefined;
541
+ /**
542
+ * This window permits failures, but no failure is necessary in it (`PermittedWindow`). The judge does not
543
+ * count a failure in it, if the failure is outside the window of the prediction and has an outcome
544
+ * of `outcomes`. Without it, each failure outside the window fails the run.
545
+ */
546
+ readonly permits?: PermittedWindow<A> | undefined;
547
+ readonly why: string;
548
+ }
549
+ /**
550
+ * A permitted window is a second window of a prediction (SYS-51). Failures can come in it, but they
551
+ * need not come. It starts `band.lo` after its reference and ends `band.hi` after it, with δ on each side.
552
+ * For example, the old holder of a VIP can send one gratuitous ARP at the heal of a lost zone. It
553
+ * sends it before it sees the loss of its lease. Each client then moves to the old node for up to one
554
+ * ARP interval.
555
+ */
556
+ interface PermittedWindow<A = Quantity> {
557
+ readonly from: Reference;
558
+ readonly band: Band<A>;
559
+ /** These outcomes are the only failures that the window permits. */
560
+ readonly outcomes: readonly string[];
532
561
  readonly why: string;
533
562
  }
534
563
  /**
@@ -644,6 +673,17 @@ interface KindCell<A = Quantity> {
644
673
  /** This flag marks a calibration: its runs measure the propagation of the endpoints, and nothing fails. */
645
674
  readonly calibrates: boolean;
646
675
  readonly runs: number;
676
+ /**
677
+ * This VIP is a Service of type LoadBalancer with an address of kube-vip in ARP mode (SYS-51). With
678
+ * it, `clients` more clients run outside the cluster, on the Docker network of the nodes, and send
679
+ * each request to the VIP. Without it, the cell has no VIP.
680
+ */
681
+ readonly vip?: VipSettings | undefined;
682
+ }
683
+ /** These are the settings of the VIP of a cell (`KindCell.vip`). */
684
+ interface VipSettings {
685
+ /** This count is the clients outside the cluster. Each one is a container on the Docker network of the nodes. */
686
+ readonly clients: number;
647
687
  }
648
688
  //#endregion
649
689
  //#region src/bands.d.ts
@@ -708,6 +748,12 @@ declare const LOG_LABEL = "lab.systems/log";
708
748
  declare const SERVER = "lab";
709
749
  declare const CLIENT = "client";
710
750
  declare const REDIS = "redis";
751
+ /** This class of a Service of type LoadBalancer selects kube-vip (pkg/kubevip/constants.go of v1.3.1). */
752
+ declare const LB_CLASS = "kube-vip.io/kube-vip-class";
753
+ /** This annotation of a Service gives kube-vip the address of its VIP (pkg/kubevip/annotations.go of v1.3.1). */
754
+ declare const VIP_ANNOTATION = "kube-vip.io/loadbalancerIPs";
755
+ /** This is the name of the node of each client outside the cluster, in its lines (`KindCell.vip`). */
756
+ declare const OUTSIDE = "outside";
711
757
  //#endregion
712
758
  //#region src/observe.d.ts
713
759
  /**
@@ -1156,7 +1202,8 @@ declare const observationAfter: (cell: Pick<KindCell, "prediction" | "workload">
1156
1202
  * for a stalled connect. It fails only at its timeout (kind run 40128267098). A reference that is not
1157
1203
  * in the lines yet does not count.
1158
1204
  *
1159
- * The band of `ends` also sets an end: its reference, the end of the band and δ.
1205
+ * The band of `ends` also sets an end: its reference, the end of the band and δ. A permitted window
1206
+ * sets an end too: its reference, the end of its band, the timeout of the workload and δ.
1160
1207
  */
1161
1208
  declare const observationEnd: (cell: KindCell, run: Pick<KindRun, "start" | "acts" | "target" | "replicas" | "lines">) => number | null;
1162
1209
  /** This function gives the facts of a run that each table reads: its failures by outcome and node, and the times of its target. */
@@ -1333,5 +1380,5 @@ declare const quantileOf: (sorted: readonly number[], p: number) => number;
1333
1380
  */
1334
1381
  declare const medianInterval: (sorted: readonly number[]) => [number, number];
1335
1382
  //#endregion
1336
- export { unitOf as $, scenario as $n, REDIS as $t, TriggerV1 as A, Template as An, recordsOf as At, RunCheck as B, KubeProxyMode as Bn, sliceReadyAt as Bt, KindCellResult as C, PodSettings as Cn, intakeOf as Ct, PredictionV1 as D, Replica as Dn, periodOf as Dt, LoadSample as E, Reference as En, outcomesOf as Et, KIND_NOISE as F, DATAPLANES as Fn, sessionsAt as Ft, factsOf as G, ZONE_LOST as Gn, transitionOf as Gt, checkRun as H, NodeImage as Hn, slicesOf as Ht, KindDecision as I, Dataplane as In, signalOf as It, observationEnd as J, goDuration as Jn, ztunnelReplaced as Jt, judgeKind as K, cidrOverlap as Kn, tunnelsOf as Kt, KindVerdict as L, KUBE_PROXY_MODES as Ln, signalsOf as Lt, upgrade as M, TriggerKind as Mn, restartOf as Mt, upgradeCell as N, WindowPrediction as Nn, restartsAt as Nt, RunCheckV1 as O, ResetReuse as On, podsAt as Ot, Deleted as P, Workload as Pn, rulesOf as Pt, reusesReset as Q, nodeNames as Qn, PORT as Qt, LAST_SLACK as R, KindConfig as Rn, sliceDropOf as Rt, KindCellRecordV1 as S, NonePrediction as Sn, failuresOf as St, KindVerdictV1 as T, RedisDeclaration as Tn, kernelCounts as Tt, cyclesOf as U, ZONE_KEPT as Un, socketsOf as Ut, RunFacts as V, NODE_IMAGES as Vn, sliceReadyOf as Vt, deletionsOf as W, ZONE_LABEL as Wn, stoppingOf as Wt, propagationSource as X, kindConfig as Xn, HEALTH_PORT as Xt, propagationOf as Y, isKubeProxyMode as Yn, CLIENT as Yt, referenceOf as Z, kubeProxyPatch as Zn, LOG_LABEL as Zt, ClusterManifest as _, KindRun as _n, byClients as _t, STAGES as a, overshootBand as an, PodLine as at, FORMAT_V1 as b, MeshFlavor as bn, dropOf as bt, readRecord as c, secondsOf as cn, Request as ct, calibrationOf as d, Band as dn, SliceLine as dt, SERVER as en, scenarioProblems as er, updatesOf as et, cellsTable as f, Cycle as fn, SocketLine as ft, BandV1 as g, KindCell as gn, backendsAt as gt, timeSpread as h, Flap as hn, ZtunnelPodLine as ht, quantileOf as i, drainBand as in, Period as it, judge as j, Trigger as jn, requestsOf as jt, RunFactsV1 as k, Stack as kn, podsOf as kt, Judged as l, showBand as ln, RulesLine as lt, predictionText as m, EdgeProtocol as mn, TunnelLine as mt, medianInterval as n, backlogEnd as nn, HBONE_PORT as nt, kindCellRecordSchema as o, requestBand as on, PropagationSource as ot, medianText as p, Declaration as pn, TCP_STATE as pt, observationAfter as q, cidrRange as qn, ztunnelPodsOf as qt, middle as r, bandOf as rn, Line as rt, kindCellRecordV1Schema as s, seconds as sn, RecordLine as st, RELATIVE as t, CountBand as tn, zoneOf as tr, Endpoint as tt, TimeSpread as u, BacklogTerm as un, Sessions as ut, EnvironmentManifest as v, KubeletProbe as vn, byNode as vt, KindCellV1 as w, Prediction as wn, isTunnelState as wt, KindCellRecord as x, MeshMode as xn, emptyOf as xt, FORMAT as y, Mesh as yn, deletionOf as yt, Propagated as z, KindScenario as zn, sliceEmptyOf as zt };
1337
- //# sourceMappingURL=judge-B_wVAwjx.d.ts.map
1383
+ export { unitOf as $, goDuration as $n, OUTSIDE as $t, TriggerV1 as A, Reference as An, recordsOf as At, RunCheck as B, DATAPLANES as Bn, sliceReadyAt as Bt, KindCellResult as C, MeshFlavor as Cn, intakeOf as Ct, PredictionV1 as D, PodSettings as Dn, periodOf as Dt, LoadSample as E, PermittedWindow as En, outcomesOf as Et, KIND_NOISE as F, Trigger as Fn, sessionsAt as Ft, factsOf as G, KubeProxyMode as Gn, transitionOf as Gt, checkRun as H, KUBE_PROXY_MODES as Hn, slicesOf as Ht, KindDecision as I, TriggerKind as In, signalOf as It, observationEnd as J, ZONE_KEPT as Jn, ztunnelReplaced as Jt, judgeKind as K, NODE_IMAGES as Kn, tunnelsOf as Kt, KindVerdict as L, VipSettings as Ln, signalsOf as Lt, upgrade as M, ResetReuse as Mn, restartOf as Mt, upgradeCell as N, Stack as Nn, restartsAt as Nt, RunCheckV1 as O, Prediction as On, podsAt as Ot, Deleted as P, Template as Pn, rulesOf as Pt, reusesReset as Q, cidrRange as Qn, LOG_LABEL as Qt, LAST_SLACK as R, WindowPrediction as Rn, sliceDropOf as Rt, KindCellRecordV1 as S, Mesh as Sn, failuresOf as St, KindVerdictV1 as T, NonePrediction as Tn, kernelCounts as Tt, cyclesOf as U, KindConfig as Un, socketsOf as Ut, RunFacts as V, Dataplane as Vn, sliceReadyOf as Vt, deletionsOf as W, KindScenario as Wn, stoppingOf as Wt, propagationSource as X, ZONE_LOST as Xn, HEALTH_PORT as Xt, propagationOf as Y, ZONE_LABEL as Yn, CLIENT as Yt, referenceOf as Z, cidrOverlap as Zn, LB_CLASS as Zt, ClusterManifest as _, EdgeProtocol as _n, byClients as _t, STAGES as a, backlogEnd as an, scenarioProblems as ar, PodLine as at, FORMAT_V1 as b, KindRun as bn, dropOf as bt, readRecord as c, overshootBand as cn, Request as ct, calibrationOf as d, secondsOf as dn, SliceLine as dt, PORT as en, isKubeProxyMode as er, updatesOf as et, cellsTable as f, showBand as fn, SocketLine as ft, BandV1 as g, Declaration as gn, backendsAt as gt, timeSpread as h, Cycle as hn, ZtunnelPodLine as ht, quantileOf as i, CountBand as in, scenario as ir, Period as it, judge as j, Replica as jn, requestsOf as jt, RunFactsV1 as k, RedisDeclaration as kn, podsOf as kt, Judged as l, requestBand as ln, RulesLine as lt, predictionText as m, Band as mn, TunnelLine as mt, medianInterval as n, SERVER as nn, kubeProxyPatch as nr, HBONE_PORT as nt, kindCellRecordSchema as o, bandOf as on, zoneOf as or, PropagationSource as ot, medianText as p, BacklogTerm as pn, TCP_STATE as pt, observationAfter as q, NodeImage as qn, ztunnelPodsOf as qt, middle as r, VIP_ANNOTATION as rn, nodeNames as rr, Line as rt, kindCellRecordV1Schema as s, drainBand as sn, RecordLine as st, RELATIVE as t, REDIS as tn, kindConfig as tr, Endpoint as tt, TimeSpread as u, seconds as un, Sessions as ut, EnvironmentManifest as v, Flap as vn, byNode as vt, KindCellV1 as w, MeshMode as wn, isTunnelState as wt, KindCellRecord as x, KubeletProbe as xn, emptyOf as xt, FORMAT as y, KindCell as yn, deletionOf as yt, Propagated as z, Workload as zn, sliceEmptyOf as zt };
1384
+ //# sourceMappingURL=judge-DpdSgpjv.d.ts.map
package/build/judge.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- import { $ as unitOf, $t as REDIS, A as TriggerV1, An as Template, At as recordsOf, B as RunCheck, Bn as KubeProxyMode, Bt as sliceReadyAt, C as KindCellResult, Cn as PodSettings, Ct as intakeOf, D as PredictionV1, Dn as Replica, Dt as periodOf, E as LoadSample, En as Reference, Et as outcomesOf, F as KIND_NOISE, Ft as sessionsAt, G as factsOf, Gt as transitionOf, H as checkRun, Ht as slicesOf, I as KindDecision, In as Dataplane, It as signalOf, J as observationEnd, Jt as ztunnelReplaced, K as judgeKind, Kt as tunnelsOf, L as KindVerdict, Lt as signalsOf, M as upgrade, Mn as TriggerKind, Mt as restartOf, N as upgradeCell, Nn as WindowPrediction, Nt as restartsAt, O as RunCheckV1, On as ResetReuse, Ot as podsAt, P as Deleted, Pn as Workload, Pt as rulesOf, Q as reusesReset, Qt as PORT, R as LAST_SLACK, Rt as sliceDropOf, S as KindCellRecordV1, Sn as NonePrediction, St as failuresOf, T as KindVerdictV1, Tn as RedisDeclaration, Tt as kernelCounts, U as cyclesOf, Ut as socketsOf, V as RunFacts, Vt as sliceReadyOf, W as deletionsOf, Wt as stoppingOf, X as propagationSource, Xt as HEALTH_PORT, Y as propagationOf, Yt as CLIENT, Z as referenceOf, Zt as LOG_LABEL, _ as ClusterManifest, _n as KindRun, _t as byClients, a as STAGES, an as overshootBand, at as PodLine, b as FORMAT_V1, bn as MeshFlavor, bt as dropOf, c as readRecord, cn as secondsOf, ct as Request, d as calibrationOf, dn as Band, dt as SliceLine, en as SERVER, et as updatesOf, f as cellsTable, fn as Cycle, ft as SocketLine, g as BandV1, gn as KindCell, gt as backendsAt, h as timeSpread, hn as Flap, ht as ZtunnelPodLine, i as quantileOf, in as drainBand, it as Period, j as judge, jn as Trigger, jt as requestsOf, k as RunFactsV1, kn as Stack, kt as podsOf, l as Judged, ln as showBand, lt as RulesLine, m as predictionText, mn as EdgeProtocol, mt as TunnelLine, n as medianInterval, nn as backlogEnd, nt as HBONE_PORT, o as kindCellRecordSchema, on as requestBand, ot as PropagationSource, p as medianText, pn as Declaration, pt as TCP_STATE, q as observationAfter, qt as ztunnelPodsOf, r as middle, rn as bandOf, rt as Line, s as kindCellRecordV1Schema, sn as seconds, st as RecordLine, t as RELATIVE, tn as CountBand, tt as Endpoint, u as TimeSpread, un as BacklogTerm, ut as Sessions, v as EnvironmentManifest, vn as KubeletProbe, vt as byNode, w as KindCellV1, wn as Prediction, wt as isTunnelState, x as KindCellRecord, xn as MeshMode, xt as emptyOf, y as FORMAT, yn as Mesh, yt as deletionOf, z as Propagated, zt as sliceEmptyOf } from "./judge-B_wVAwjx.js";
2
- export { type BacklogTerm, type Band, type BandV1, CLIENT, type ClusterManifest, type CountBand, type Cycle, type Dataplane, type Declaration, type Deleted, type EdgeProtocol, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type Flap, HBONE_PORT, HEALTH_PORT, type Judged, KIND_NOISE, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindDecision, type KindRun, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshMode, type NonePrediction, PORT, Period, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, SERVER, STAGES, Sessions, SliceLine, SocketLine, type Stack, TCP_STATE, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
1
+ import { $ as unitOf, $t as OUTSIDE, A as TriggerV1, An as Reference, At as recordsOf, B as RunCheck, Bt as sliceReadyAt, C as KindCellResult, Cn as MeshFlavor, Ct as intakeOf, D as PredictionV1, Dn as PodSettings, Dt as periodOf, E as LoadSample, En as PermittedWindow, Et as outcomesOf, F as KIND_NOISE, Fn as Trigger, Ft as sessionsAt, G as factsOf, Gn as KubeProxyMode, Gt as transitionOf, H as checkRun, Ht as slicesOf, I as KindDecision, In as TriggerKind, It as signalOf, J as observationEnd, Jt as ztunnelReplaced, K as judgeKind, Kt as tunnelsOf, L as KindVerdict, Ln as VipSettings, Lt as signalsOf, M as upgrade, Mn as ResetReuse, Mt as restartOf, N as upgradeCell, Nn as Stack, Nt as restartsAt, O as RunCheckV1, On as Prediction, Ot as podsAt, P as Deleted, Pn as Template, Pt as rulesOf, Q as reusesReset, Qt as LOG_LABEL, R as LAST_SLACK, Rn as WindowPrediction, Rt as sliceDropOf, S as KindCellRecordV1, Sn as Mesh, St as failuresOf, T as KindVerdictV1, Tn as NonePrediction, Tt as kernelCounts, U as cyclesOf, Ut as socketsOf, V as RunFacts, Vn as Dataplane, Vt as sliceReadyOf, W as deletionsOf, Wt as stoppingOf, X as propagationSource, Xt as HEALTH_PORT, Y as propagationOf, Yt as CLIENT, Z as referenceOf, Zt as LB_CLASS, _ as ClusterManifest, _n as EdgeProtocol, _t as byClients, a as STAGES, an as backlogEnd, at as PodLine, b as FORMAT_V1, bn as KindRun, bt as dropOf, c as readRecord, cn as overshootBand, ct as Request, d as calibrationOf, dn as secondsOf, dt as SliceLine, en as PORT, et as updatesOf, f as cellsTable, fn as showBand, ft as SocketLine, g as BandV1, gn as Declaration, gt as backendsAt, h as timeSpread, hn as Cycle, ht as ZtunnelPodLine, i as quantileOf, in as CountBand, it as Period, j as judge, jn as Replica, jt as requestsOf, k as RunFactsV1, kn as RedisDeclaration, kt as podsOf, l as Judged, ln as requestBand, lt as RulesLine, m as predictionText, mn as Band, mt as TunnelLine, n as medianInterval, nn as SERVER, nt as HBONE_PORT, o as kindCellRecordSchema, on as bandOf, ot as PropagationSource, p as medianText, pn as BacklogTerm, pt as TCP_STATE, q as observationAfter, qt as ztunnelPodsOf, r as middle, rn as VIP_ANNOTATION, rt as Line, s as kindCellRecordV1Schema, sn as drainBand, st as RecordLine, t as RELATIVE, tn as REDIS, tt as Endpoint, u as TimeSpread, un as seconds, ut as Sessions, v as EnvironmentManifest, vn as Flap, vt as byNode, w as KindCellV1, wn as MeshMode, wt as isTunnelState, x as KindCellRecord, xn as KubeletProbe, xt as emptyOf, y as FORMAT, yn as KindCell, yt as deletionOf, z as Propagated, zn as Workload, zt as sliceEmptyOf } from "./judge-DpdSgpjv.js";
2
+ export { type BacklogTerm, type Band, type BandV1, CLIENT, type ClusterManifest, type CountBand, type Cycle, type Dataplane, type Declaration, type Deleted, type EdgeProtocol, Endpoint, type EnvironmentManifest, FORMAT, FORMAT_V1, type Flap, HBONE_PORT, HEALTH_PORT, type Judged, KIND_NOISE, type KindCell, type KindCellRecord, type KindCellRecordV1, type KindCellResult, type KindCellV1, type KindDecision, type KindRun, type KindVerdict, type KindVerdictV1, type KubeProxyMode, type KubeletProbe, LAST_SLACK, LB_CLASS, LOG_LABEL, Line, type LoadSample, type Mesh, type MeshFlavor, type MeshMode, type NonePrediction, OUTSIDE, PORT, Period, type PermittedWindow, PodLine, type PodSettings, type Prediction, type PredictionV1, type Propagated, PropagationSource, REDIS, RELATIVE, RecordLine, type RedisDeclaration, type Reference, type Replica, Request, type ResetReuse, RulesLine, type RunCheck, type RunCheckV1, type RunFacts, type RunFactsV1, SERVER, STAGES, Sessions, SliceLine, SocketLine, type Stack, TCP_STATE, type Template, type TimeSpread, type Trigger, type TriggerKind, type TriggerV1, TunnelLine, VIP_ANNOTATION, type VipSettings, type WindowPrediction, type Workload, ZtunnelPodLine, backendsAt, backlogEnd, bandOf, byClients, byNode, calibrationOf, cellsTable, checkRun, cyclesOf, deletionOf, deletionsOf, drainBand, dropOf, emptyOf, factsOf, failuresOf, intakeOf, isTunnelState, judge, judgeKind, kernelCounts, kindCellRecordSchema, kindCellRecordV1Schema, medianInterval, medianText, middle, observationAfter, observationEnd, outcomesOf, overshootBand, periodOf, podsAt, podsOf, predictionText, propagationOf, propagationSource, quantileOf, readRecord, recordsOf, referenceOf, requestBand, requestsOf, restartOf, restartsAt, reusesReset, rulesOf, seconds, secondsOf, sessionsAt, showBand, signalOf, signalsOf, sliceDropOf, sliceEmptyOf, sliceReadyAt, sliceReadyOf, slicesOf, socketsOf, stoppingOf, timeSpread, transitionOf, tunnelsOf, unitOf, updatesOf, upgrade, upgradeCell, ztunnelPodsOf, ztunnelReplaced };
package/build/judge.js CHANGED
@@ -1 +1 @@
1
- export { ht as CLIENT, u as FORMAT, d as FORMAT_V1, A as HBONE_PORT, gt as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, _t as LOG_LABEL, vt as PORT, yt as REDIS, dt as RELATIVE, bt as SERVER, t as STAGES, j as TCP_STATE, M as backendsAt, xt as backlogEnd, St as bandOf, N as byClients, P as byNode, a as calibrationOf, o as cellsTable, _ as checkRun, v as cyclesOf, F as deletionOf, y as deletionsOf, Ct as drainBand, I as dropOf, L as emptyOf, b as factsOf, R as failuresOf, z as intakeOf, B as isTunnelState, f as judge, x as judgeKind, V as kernelCounts, n as kindCellRecordSchema, r as kindCellRecordV1Schema, ft as medianInterval, s as medianText, pt as middle, S as observationAfter, C as observationEnd, H as outcomesOf, wt as overshootBand, U as periodOf, W as podsAt, G as podsOf, c as predictionText, w as propagationOf, T as propagationSource, mt as quantileOf, i as readRecord, K as recordsOf, E as referenceOf, Tt as requestBand, q as requestsOf, J as restartOf, Y as restartsAt, D as reusesReset, X as rulesOf, Et as seconds, Dt as secondsOf, Z as sessionsAt, Ot as showBand, Q as signalOf, $ as signalsOf, et as sliceDropOf, tt as sliceEmptyOf, nt as sliceReadyAt, rt as sliceReadyOf, it as slicesOf, at as socketsOf, ot as stoppingOf, l as timeSpread, st as transitionOf, ct as tunnelsOf, O as unitOf, k as updatesOf, p as upgrade, m as upgradeCell, lt as ztunnelPodsOf, ut as ztunnelReplaced } from "./judge-Bc84w-no.js";
1
+ export { ht as CLIENT, u as FORMAT, d as FORMAT_V1, A as HBONE_PORT, gt as HEALTH_PORT, h as KIND_NOISE, g as LAST_SLACK, _t as LB_CLASS, vt as LOG_LABEL, yt as OUTSIDE, bt as PORT, xt as REDIS, dt as RELATIVE, St as SERVER, t as STAGES, j as TCP_STATE, Ct as VIP_ANNOTATION, M as backendsAt, wt as backlogEnd, Tt as bandOf, N as byClients, P as byNode, a as calibrationOf, o as cellsTable, _ as checkRun, v as cyclesOf, F as deletionOf, y as deletionsOf, Et as drainBand, I as dropOf, L as emptyOf, b as factsOf, R as failuresOf, z as intakeOf, B as isTunnelState, f as judge, x as judgeKind, V as kernelCounts, n as kindCellRecordSchema, r as kindCellRecordV1Schema, ft as medianInterval, s as medianText, pt as middle, S as observationAfter, C as observationEnd, H as outcomesOf, Dt as overshootBand, U as periodOf, W as podsAt, G as podsOf, c as predictionText, w as propagationOf, T as propagationSource, mt as quantileOf, i as readRecord, K as recordsOf, E as referenceOf, Ot as requestBand, q as requestsOf, J as restartOf, Y as restartsAt, D as reusesReset, X as rulesOf, kt as seconds, At as secondsOf, Z as sessionsAt, jt as showBand, Q as signalOf, $ as signalsOf, et as sliceDropOf, tt as sliceEmptyOf, nt as sliceReadyAt, rt as sliceReadyOf, it as slicesOf, at as socketsOf, ot as stoppingOf, l as timeSpread, st as transitionOf, ct as tunnelsOf, O as unitOf, k as updatesOf, p as upgrade, m as upgradeCell, lt as ztunnelPodsOf, ut as ztunnelReplaced } from "./judge-C7Zr4KoS.js";
package/image/Dockerfile CHANGED
@@ -1,7 +1,8 @@
1
1
  # The image of a kind cell: the service on @mark1russell7/service, its clients (HTTP and grpc-js),
2
2
  # the agent of each node and the watcher of the API, on Node 24.21.0. The base is pinned by digest,
3
3
  # and npm-lock.json pins the packages from npm. The packages of the workspace come as the tarballs
4
- # that pnpm packs, and the build unpacks them over node_modules, as npm would install them. image.ts
4
+ # that pnpm packs, and the build unpacks them over node_modules, as npm would install them. The unpack
5
+ # installs no dependency, thus package.json also lists each dependency from npm of those packages. image.ts
5
6
  # stages the context, and the resolver of the harness builds it with a tag from its content.
6
7
  FROM node:24.21.0-alpine@sha256:ebfe2f90462722a7a4de65e91990e97fe0d401c70e0e762c5b53302f905ec1c1
7
8
  WORKDIR /opt/lab
package/image/client.mjs CHANGED
@@ -170,6 +170,31 @@ const flush = () => {
170
170
  setInterval(flush, 100);
171
171
  const say = (line) => pending.push(`${JSON.stringify({ ...line, p: pod, n: node })}\n`);
172
172
 
173
+ // With ARP_WATCH, the client reads the MAC address of that IPv4 address in the neighbour table each
174
+ // 10 ms, and it writes a line `arp` at each change (SYS-51). A gratuitous ARP of a new holder of a VIP
175
+ // changes the MAC, thus the line gives the time of the move. An entry with the flags 0x0 has no MAC yet
176
+ const watched = process.env.ARP_WATCH ?? "";
177
+ if (watched !== "") {
178
+ let seen;
179
+ setInterval(() => {
180
+ let mac = null;
181
+ try {
182
+ for (const row of readFileSync("/proc/net/arp", "utf8").split("\n").slice(1)) {
183
+ const [ip, , flags, hw] = row.trim().split(/\s+/);
184
+ if (ip === watched) {
185
+ mac = flags === "0x0" ? null : hw.toLowerCase();
186
+ break;
187
+ }
188
+ }
189
+ } catch {
190
+ return;
191
+ }
192
+ if (mac === seen) return;
193
+ seen = mac;
194
+ say({ ev: "arp", t: now(), ip: watched, mac });
195
+ }, 10);
196
+ }
197
+
173
198
  const outcomeOf = (error) => {
174
199
  const code = error?.code ?? "";
175
200
  if (code === "ECONNREFUSED") return "refused";
@@ -7,6 +7,8 @@
7
7
  "name": "systems-kind-lab",
8
8
  "dependencies": {
9
9
  "@grpc/grpc-js": "1.14.6",
10
+ "@mark1russell7/rational": "0.1.0",
11
+ "@mark1russell7/rigor-generators": "0.1.0",
10
12
  "ioredis": "6.0.0",
11
13
  "zod": "4.6.6"
12
14
  }
@@ -58,6 +60,24 @@
58
60
  "url": "https://opencollective.com/js-sdsl"
59
61
  }
60
62
  },
63
+ "node_modules/@mark1russell7/rational": {
64
+ "version": "0.1.0",
65
+ "resolved": "https://registry.npmjs.org/@mark1russell7/rational/-/rational-0.1.0.tgz",
66
+ "integrity": "sha512-kYUuKI9STA4mlCpJCx/FpUSe8sokryDJzSuyd/Abev9Len7lotztPEOPH4A8WoxLvEsKEwHA33kg7lbLVjGZWw==",
67
+ "license": "MIT",
68
+ "engines": {
69
+ "node": ">=22"
70
+ }
71
+ },
72
+ "node_modules/@mark1russell7/rigor-generators": {
73
+ "version": "0.1.0",
74
+ "resolved": "https://registry.npmjs.org/@mark1russell7/rigor-generators/-/rigor-generators-0.1.0.tgz",
75
+ "integrity": "sha512-xhXvLzZQlDH6ysAbqEjbha6fs1GbvO9RflSXwYbA3QMryxu4zEikbxahEDQCIxVSis+2pfX/18PHU3+X+jJmPw==",
76
+ "license": "MIT",
77
+ "engines": {
78
+ "node": ">=22"
79
+ }
80
+ },
61
81
  "node_modules/@protobufjs/aspromise": {
62
82
  "version": "1.1.2",
63
83
  "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
@@ -4,6 +4,8 @@
4
4
  "type": "module",
5
5
  "dependencies": {
6
6
  "@grpc/grpc-js": "1.14.6",
7
+ "@mark1russell7/rational": "0.1.0",
8
+ "@mark1russell7/rigor-generators": "0.1.0",
7
9
  "ioredis": "6.0.0",
8
10
  "zod": "4.6.6"
9
11
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package",
3
3
  "name": "@mark1russell7/kind",
4
- "version": "0.13.0",
4
+ "version": "0.13.2",
5
5
  "description": "Kubernetes in Docker as a lab for connection timers: a kind cluster from a scenario, faults in the namespaces of its pods, observations on the one monotonic clock of the VM, and predictions from the ordering law. Its judge entry reads and judges a raw record without Docker.",
6
6
  "keywords": [
7
7
  "kubernetes",