@downtrace/protocol 0.8.0 → 0.10.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.
Files changed (36) hide show
  1. package/README.md +25 -1
  2. package/dist/index.d.ts +430 -24
  3. package/dist/index.js +325 -26
  4. package/package.json +1 -1
  5. package/schema/v0/aggregates.schema.json +112 -17
  6. package/schema/v0/capture-evidence.schema.json +154 -4
  7. package/schema/v0/fixtures/evidence/invalid/coarse-second-without-its-calls.json +20 -0
  8. package/schema/v0/fixtures/evidence/invalid/dependencies-truncated-negative.json +14 -0
  9. package/schema/v0/fixtures/evidence/invalid/dependencies-truncated-not-a-boolean.json +24 -0
  10. package/schema/v0/fixtures/evidence/invalid/operation-of-an-unknown-kind.json +33 -0
  11. package/schema/v0/fixtures/evidence/invalid/shed-with-an-extra-field.json +14 -0
  12. package/schema/v0/fixtures/evidence/invalid/shed-with-unknown-reason.json +14 -0
  13. package/schema/v0/fixtures/evidence/invalid/shed-with-zero-ms.json +14 -0
  14. package/schema/v0/fixtures/evidence/valid/with-coarse.json +40 -0
  15. package/schema/v0/fixtures/evidence/valid/with-dependencies-truncated.json +32 -0
  16. package/schema/v0/fixtures/evidence/valid/with-operation-kinds.json +57 -0
  17. package/schema/v0/fixtures/evidence/valid/with-shed.json +31 -0
  18. package/schema/v0/fixtures/invalid/a-running-total-of-nothing.json +27 -0
  19. package/schema/v0/fixtures/invalid/an-ending-nobody-declared.json +46 -0
  20. package/schema/v0/fixtures/invalid/call-with-a-path.json +38 -0
  21. package/schema/v0/fixtures/invalid/call-with-a-query-string.json +38 -0
  22. package/schema/v0/fixtures/invalid/command-with-its-key.json +38 -0
  23. package/schema/v0/fixtures/invalid/context-that-is-not-flat.json +40 -0
  24. package/schema/v0/fixtures/invalid/error-sources-with-a-call.json +49 -0
  25. package/schema/v0/fixtures/invalid/error-sources-with-a-query.json +49 -0
  26. package/schema/v0/fixtures/invalid/error-sources-with-a-repeat.json +49 -0
  27. package/schema/v0/fixtures/invalid/error-sources-with-an-unknown-value.json +49 -0
  28. package/schema/v0/fixtures/invalid/operation-of-an-unknown-kind.json +37 -0
  29. package/schema/v0/fixtures/valid/calls-and-commands.json +59 -0
  30. package/schema/v0/fixtures/valid/dropped-exceptions.json +56 -0
  31. package/schema/v0/fixtures/valid/error-sources.json +49 -0
  32. package/schema/v0/fixtures/valid/exceptions-with-a-running-total.json +38 -0
  33. package/schema/v0/fixtures/valid/exceptions-without-intervals.json +37 -0
  34. package/schema/v0/fixtures/valid/reported-errors.json +97 -0
  35. package/schema/v0/fixtures/valid/the-last-batch-of-a-process.json +59 -0
  36. package/schema/v0/fixtures/valid/triggers-without-intervals.json +28 -0
package/dist/index.d.ts CHANGED
@@ -11,6 +11,14 @@ declare function captureEvidencePath(id: string): string;
11
11
  * Whether an observer is attached (`on`), was not asked for (`off`), or was asked for and could not attach (`unavailable`) — a driver that is not resolvable from the application's root, for instance. The third one is the point: without it, a service that is not being watched looks exactly like a service that has nothing to watch (COB-01, invariant 14).
12
12
  */
13
13
  type ObserverState = "on" | "off" | "unavailable";
14
+ /**
15
+ * A value of `Operation.kind` that its `x-error` marks as an error: the ways an error inside a request arrives, and so the sources that can produce one. A query, an outgoing call and a Redis command are things a route ran, never a source of error.
16
+ */
17
+ type InRequestErrorSource = "error" | "framework" | "explicit";
18
+ /**
19
+ * A value of `ProcessException.kind`: the ways an error outside any request arrives, and so the sources that can produce one.
20
+ */
21
+ type OutsideRequestErrorSource = "uncaught" | "unhandled-rejection" | "framework" | "explicit";
14
22
  /**
15
23
  * A batch of per-interval, per-route aggregates sent by an agent to the cloud (POST /v0/aggregates).
16
24
  */
@@ -18,12 +26,12 @@ interface AggregatesBatch {
18
26
  /**
19
27
  * Protocol version this batch conforms to. Every published minor of v0 stays acceptable.
20
28
  */
21
- protocol: "0.1.0" | "0.2.0" | "0.3.0" | "0.4.0" | "0.5.0" | "0.6.0" | "0.7.0" | "0.8.0";
29
+ protocol: "0.1.0" | "0.2.0" | "0.3.0" | "0.4.0" | "0.5.0" | "0.6.0" | "0.7.0" | "0.8.0" | "0.9.0" | "0.10.0";
22
30
  agent: AgentInfo;
23
31
  instance: InstanceInfo;
24
32
  deploy: DeployInfo;
25
33
  /**
26
- * The intervals this batch carries. May be empty when the batch carries a profile: the profile has a cadence of its own and hangs off the batch, not off an interval (ADR 0017), so tying its delivery to one meant it was lost whenever a window closed with no traffic — at shutdown, always (gh-375). A batch with neither is refused by the cloud with a reason, which the schema cannot say without making the generated types unusable.
34
+ * The intervals this batch carries. May be empty whenever the batch carries anything else: a process that serves no requests closes no interval, and nothing else a batch carries hangs off one — tying delivery to an interval lost the profile at every shutdown (gh-375) and every exception of a process with no traffic (gh-627). A batch that carries nothing at all is refused by the cloud with a reason, which the schema cannot say without making the generated types unusable.
27
35
  *
28
36
  * @minItems 0
29
37
  * @maxItems 6
@@ -43,11 +51,15 @@ interface AggregatesBatch {
43
51
  */
44
52
  exceptions?: ProcessException[];
45
53
  /**
46
- * Local signals that ask for a capture. `product.md:124` gives the instrumentation «disparar por señales locales»: it sees a process in trouble before any aggregate crosses the cloud, and asking in the batch costs no channel of its own — the answer already carries the orders (ADR 0071). Absent from every sender that predates it and from every batch with nothing to ask. The cloud decides: the same budget, cooldown and concurrency as any other capture (`product.md:122`), and a refusal is silence, because there is nothing the instrumentation would do differently.
54
+ * Local signals that ask for a capture. `product.md:124` gives the instrumentation «trigger on local signals»: it sees a process in trouble before any aggregate crosses the cloud, and asking in the batch costs no channel of its own — the answer already carries the orders (ADR 0071). Absent from every sender that predates it and from every batch with nothing to ask. The cloud decides: the same budget, cooldown and concurrency as any other capture (`product.md:122`), and a refusal is silence, because there is nothing the instrumentation would do differently.
47
55
  *
48
56
  * @maxItems 4
49
57
  */
50
58
  triggers?: [] | [LocalTrigger] | [LocalTrigger, LocalTrigger] | [LocalTrigger, LocalTrigger, LocalTrigger] | [LocalTrigger, LocalTrigger, LocalTrigger, LocalTrigger];
59
+ /**
60
+ * This batch is the last one: the process is leaving deliberately and has already been handed everything the instrumentation was holding. `signal`, a SIGTERM or SIGINT the instrumentation's own handler saw; `exit`, an application that awaited `shutdown()` before calling `process.exit()`; `idle`, an event loop that emptied. Absent means **this sender did not say**, the same reading as `observers` — never that it ended badly: an instrumentation older than this never says it, and a process an exception killed says nothing because it cannot. It is the half of ERR-04 the cloud cannot infer — from outside, every ending looks like batches stopping — and it carries no instant, because the one that matters is when the batch arrived, which the cloud measures.
61
+ */
62
+ ending?: "signal" | "exit" | "idle";
51
63
  }
52
64
  interface AgentInfo {
53
65
  name: string;
@@ -57,6 +69,7 @@ interface AgentInfo {
57
69
  observers?: Observers;
58
70
  withholding?: Withholding;
59
71
  resources?: AgentResources;
72
+ errorSources?: ErrorSources;
60
73
  }
61
74
  /**
62
75
  * Absent from an instrumentation older than protocol 0.7.0. Absent is not 'nothing is observed': it is 'this one did not say', and the two must not be shown alike.
@@ -85,7 +98,7 @@ interface Withholding {
85
98
  dependencies?: number;
86
99
  }
87
100
  /**
88
- * What the instrumentation costs and what it has lost, measured by itself. Absent means **this sender did not say**, the same reading as `observers` and `withholding`. `product.md:239` asks for it by name: «recursos internos medidos».
101
+ * What the instrumentation costs and what it has lost, measured by itself. Absent means **this sender did not say**, the same reading as `observers` and `withholding`. `product.md:239` asks for it by name: «measured internal resources».
89
102
  */
90
103
  interface AgentResources {
91
104
  /**
@@ -104,6 +117,10 @@ interface AgentResources {
104
117
  * Errors inside the instrumentation itself, since the previous batch. It disables itself after enough of them, and a sender that has gone quiet with these climbing is not a quiet service.
105
118
  */
106
119
  internalErrors?: number;
120
+ /**
121
+ * Exception events the instrumentation discarded because they did not fit in its caps of distinct signatures — the register's window, and the sender's accumulation while batches do not land — since the previous batch. An occurrence, never a signature: the sender cannot name what it did not admit without remembering it, and remembering is the growth the cap exists to stop. This is what happened and is gone, the same kind of number as droppedBatches, for the errors a process throws outside any request: a batch that says 32 and was handed 35 must not leave the other 3 to be read as errors that did not happen (COB-01, invariant 14).
122
+ */
123
+ droppedExceptions?: number;
107
124
  /**
108
125
  * What the black box's registers have allocated, right now. An instant, and arithmetic rather than a measurement: the rings are preallocated.
109
126
  */
@@ -113,7 +130,7 @@ interface AgentResources {
113
130
  */
114
131
  hookMsPerRequest?: number;
115
132
  /**
116
- * What the instrumentation has given up because it was costing too much, cheapest loss first. `product.md:241` asks for both halves —«se autolimita» and «lo registra como pérdida de cobertura»— and this is the second. An enum and not free text: it is ours, and it has to be comparable between senders.
133
+ * What the instrumentation has given up because it was costing too much, cheapest loss first. `product.md:241` asks for both halves —«it throttles itself» and «records it as a loss of coverage»— and this is the second. An enum and not free text: it is ours, and it has to be comparable between senders.
117
134
  */
118
135
  shed?: "nothing" | "fine" | "profile";
119
136
  /**
@@ -121,6 +138,19 @@ interface AgentResources {
121
138
  */
122
139
  shedReason?: "latency" | "memory";
123
140
  }
141
+ /**
142
+ * Which of the sources of error this process has connected, as of the moment this batch is sealed. A source is on its list when the process has, at that moment, the instrumentation that produces it installed; the application calling `captureException` does not make it one without the hook connected. Absent means **this sender did not say**, the same reading as `observers` and `resources`: an instrumentation older than protocol 0.9.0 says nothing, and the two lists left empty are not the same thing, because they are a statement — the sender says it has connected no source of error.
143
+ */
144
+ interface ErrorSources {
145
+ /**
146
+ * The sources of the errors this process sees inside a request, by the value of `Operation.kind` they arrive as, among the values `x-error` marks as errors: `error`, an instrumented operation failed; `framework`, the exception reached the framework's error path and was turned into a 5xx; `explicit`, the application handed it over itself. No value appears twice.
147
+ */
148
+ inRequest: InRequestErrorSource[];
149
+ /**
150
+ * The sources of the errors this process sees outside any request, by the value of `ProcessException.kind`: `uncaught`, an exception nothing caught; `unhandled-rejection`, a promise rejected with nothing to handle it; `framework`, one that reached a framework's error path; `explicit`, one the application handed over itself. No value appears twice.
151
+ */
152
+ outsideRequest: OutsideRequestErrorSource[];
153
+ }
124
154
  interface InstanceInfo {
125
155
  /**
126
156
  * Random identifier generated once per process.
@@ -151,7 +181,7 @@ interface Interval {
151
181
  interface Endpoint {
152
182
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "OTHER";
153
183
  /**
154
- * Normalised route template, e.g. /products/:id, or (other).
184
+ * Normalised route template, e.g. /products/:id, or a name that is not a route: (other), what the interval's cap on routes left out, or (unmatched), the requests that no route of the framework named (DT-56).
155
185
  */
156
186
  route: string;
157
187
  count: number;
@@ -230,9 +260,9 @@ interface PostgresStats {
230
260
  */
231
261
  interface Dependency {
232
262
  /**
233
- * What kind of dependency this is.
263
+ * What kind of dependency this is. `mongodb` since 0.10.0: a MongoDB database, whose commands are operations of kind `query` named by the command and the collection (`find users`).
234
264
  */
235
- kind: "postgres" | "mysql" | "redis" | "http";
265
+ kind: "postgres" | "mysql" | "mongodb" | "redis" | "http";
236
266
  /**
237
267
  * Host for outgoing HTTP (`api.stripe.com`); empty when the dependency is a single one, like the application's own database.
238
268
  */
@@ -320,7 +350,7 @@ interface Profile {
320
350
  interface ProfileEndpoint {
321
351
  method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD" | "OPTIONS" | "OTHER";
322
352
  /**
323
- * Normalised route template, e.g. /products/:id, or (other).
353
+ * Normalised route template, e.g. /products/:id, or a name that is not a route: (other), what the interval's cap on routes left out, or (unmatched), the requests that no route of the framework named (DT-56).
324
354
  */
325
355
  route: string;
326
356
  /**
@@ -333,15 +363,15 @@ interface ProfileEndpoint {
333
363
  */
334
364
  interface Operation {
335
365
  /**
336
- * What kind of operation this is.
366
+ * What kind of operation this is. Three are things the route ran: `query`, a query to a database; `call`, an outgoing HTTP call, identified by its method and its host; `command`, a Redis command, identified by its name and its server. The other three are errors, and which one it is says how the instrumentation came to see it: `error`, an instrumented operation failed; `framework`, the exception reached the framework's error path and was turned into a 5xx; `explicit`, the application handed it over itself (ERR-02). `x-since` says which minor first carries each value, which is how a reader tells a kind a sender cannot send from one it did not; `x-error` says which values are errors, which is what a list of errors takes and the rest never reach (ERR-01).
337
367
  */
338
- kind: "query" | "error";
368
+ kind: "query" | "error" | "framework" | "explicit" | "call" | "command";
339
369
  /**
340
370
  * Stable identity of the operation, or `(other)` for the bucket that holds the rest.
341
371
  */
342
372
  hash: string;
343
373
  /**
344
- * Normalised text, e.g. `SELECT id FROM products WHERE id = ?`. Optional: a user who would rather not send it keeps the whole analysis, only without the label.
374
+ * Normalised text, e.g. `SELECT id FROM products WHERE id = ?` for a query, `find users` for a MongoDB command — its name and its collection, never the filter or the documents —, `POST api.stripe.com` for a call and `HGETALL cache:6379` for a command. A call's and a command's are a word and the place it went — the method and the host, the command's name and its server — and never a path, a query string, a key or an argument (invariant 5): the schema refuses one with anything after the place, or a slash, a question mark or a hash in it. Optional: a user who would rather not send it keeps the whole analysis, only without the label, and a sender in minimal mode, or one withholding the name of the dependency, sends none.
345
375
  */
346
376
  text?: string;
347
377
  /**
@@ -360,11 +390,18 @@ interface Operation {
360
390
  * Only on the `(other)` bucket: how many distinct operations it merges, so a cap does not become a lie by omission.
361
391
  */
362
392
  distinct?: number;
393
+ context?: ReportedContext;
363
394
  /**
364
- * What kind of statement this is, when the sender could not normalise it safely. Its presence is the reason the text is absent: `product.md:104` says a query the normaliser does not understand travels «solo como hash y clase», and this is the class. Never sent together with `text` — they are two answers to the same question. Our word and not the service's: it is decided from the first keyword, which is all that can be told without understanding the rest (gh-344).
395
+ * What kind of statement this is, when the sender could not normalise it safely. Its presence is the reason the text is absent: `product.md:104` says a query the normaliser does not understand travels «only as hash and class», and this is the class. Never sent together with `text` — they are two answers to the same question. Our word and not the service's: it is decided from the first keyword, which is all that can be told without understanding the rest (gh-344).
365
396
  */
366
397
  class?: "select" | "insert" | "update" | "delete" | "other";
367
398
  }
399
+ /**
400
+ * The structural context an application attached to an error it reported (ERR-02, since 0.9.0). Flat and small on purpose: what travels is the shape of the failure, never its contents (invariant 5). Every value has been through the same sanitising as an error message before it got here, so anything that looked like a value is already a `?`, and there is nothing per user in it (IMP-01). It is the context of the **first** occurrence of the signature in this window, because what travels is counted per signature and not per occurrence. Absent is the normal case: an error nobody attached a context to carries none.
401
+ */
402
+ interface ReportedContext {
403
+ [k: string]: string;
404
+ }
368
405
  /**
369
406
  * What the instrumentation has to say about a capture the cloud asked it for. The order travels in the ingest response (ADR 0071) and the answer travels here, on the same cadence and at the same cost: a path of its own would be one more call per capture, and one more thing to authenticate, for a fact that fits in the batch that is already going (gh-378).
370
407
  */
@@ -379,13 +416,13 @@ interface CaptureProgress {
379
416
  startedAt: number;
380
417
  }
381
418
  /**
382
- * Something thrown outside any instrumented operation: an exception nobody caught, or a promise rejected with no `catch`. `product.md:77` asks for «errores **y excepciones**», and these are the two the word «excepciones» names. They live on the batch and not in the profile because they have **no route** — they happen outside a request's life, or after it ended — and filing them under a route that is not theirs would be worse than not having them (gh-341, ADR 0102).
419
+ * Something thrown outside any instrumented operation: an exception nobody caught, or a promise rejected with no `catch`. `product.md:77` asks for «errors and exceptions», and these are the two the word «excepciones» names. They live on the batch and not in the profile because they have **no route** — they happen outside a request's life, or after it ended — and filing them under a route that is not theirs would be worse than not having them (gh-341, ADR 0102).
383
420
  */
384
421
  interface ProcessException {
385
422
  /**
386
- * Which of the two. Two different failures with two different fixes: counting them together hides which one is happening.
423
+ * How the process came to see it. `uncaught` and `unhandled-rejection` are two different failures with two different fixes, and counting them together hides which one is happening. `explicit` is an error the application handed over while no request was being served, and `framework` one that reached a framework's error path outside any observed request — a process that is not opening request contexts at all (ERR-02). `x-since` says which minor first carries each value.
387
424
  */
388
- kind: "uncaught" | "unhandled-rejection";
425
+ kind: "uncaught" | "unhandled-rejection" | "framework" | "explicit";
389
426
  /**
390
427
  * Stable identity of the signature, the same shape a query's or an operation error's has (ADR 0017).
391
428
  */
@@ -395,9 +432,14 @@ interface ProcessException {
395
432
  */
396
433
  text?: string;
397
434
  /**
398
- * How many times this signature happened. An instant per occurrence would be a row per crash of a process that crashes in a loop; what a reader asks is how many.
435
+ * How many times this signature happened since the last delivery this sender heard land. An instant per occurrence would be a row per crash of a process that crashes in a loop; what a reader asks is how many.
399
436
  */
400
437
  count: number;
438
+ /**
439
+ * Since 0.9.0: how many times this signature has happened in this instance since it started, a running total every delivery of the signature carries again. It is what lets the cloud tell a delivery it already applied from one that happened again (gh-625): `total - count` is what the sender knows was applied, the cloud keeps the largest total it applied per instance and signature, and it counts only what this delivery adds beyond both — so a delivery sent again after its answer was lost, sent twice, or overtaken by a later one adds nothing, and one that never arrived is counted by the next. It never goes down while `instance.id` stays the same, which is why that id is generated once per process. Absent from every sender older than this, and from a signature past the number a sender keeps totals for: the cloud then counts `count` as delivered, and says so.
440
+ */
441
+ total?: number;
442
+ context?: ReportedContext;
401
443
  }
402
444
  /**
403
445
  * One local signal, sustained past its threshold. It asks for detail; it does not claim a cause (invariant 7).
@@ -435,15 +477,23 @@ declare const CALLS_PER_REQUEST_BOUNDARIES_V0: readonly number[];
435
477
  /** Number of calls-per-request buckets: boundaries + 1 open-ended bucket. */
436
478
  declare const CALLS_PER_REQUEST_BUCKETS_V0 = 8;
437
479
  //#endregion
480
+ //#region src/generated/caps.d.ts
481
+ /** The most dependencies one endpoint may carry in a batch. */
482
+ declare const DEPENDENCIES_MAX_ITEMS_V0 = 64;
483
+ /** The most requests a capture's evidence may carry: the ring is sized as this minus the reserves' room (gh-901). */
484
+ declare const EVIDENCE_REQUESTS_MAX_ITEMS_V0 = 4096;
485
+ /** The dependency kinds the schema names, in the order it names them. */
486
+ declare const DEPENDENCY_KINDS_V0: readonly ["postgres", "mysql", "mongodb", "redis", "http"];
487
+ //#endregion
438
488
  //#region src/generated/capture-evidence.d.ts
439
489
  /**
440
- * What an instrumentation sends back for a capture the cloud asked for (POST /v0/captures/{id}/evidence). It is the contents of the black box's fine register, frozen: requests with their operations, in order, with starts and ends. Hashes only — the text of a query never travels here (invariant 5). Its own path and not the aggregates batch, because a batch is what goes out every ten seconds and this is a rare event several orders of magnitude larger.
490
+ * What an instrumentation sends back for a capture the cloud asked for (POST /v0/captures/{id}/evidence). It is the contents of the black box, frozen: the fine register's requests with their operations, in order, with starts and ends, and the coarse summary of the previous minutes, second by second. Hashes only — the text of a query never travels here (invariant 5). Its own path and not the aggregates batch, because a batch is what goes out every ten seconds and this is a rare event several orders of magnitude larger.
441
491
  */
442
492
  interface CaptureEvidence {
443
493
  /**
444
494
  * Protocol version this payload conforms to. Same enum as a batch: every published minor of v0 stays acceptable.
445
495
  */
446
- protocol: "0.1.0" | "0.2.0" | "0.3.0" | "0.4.0" | "0.5.0" | "0.6.0" | "0.7.0" | "0.8.0";
496
+ protocol: "0.1.0" | "0.2.0" | "0.3.0" | "0.4.0" | "0.5.0" | "0.6.0" | "0.7.0" | "0.8.0" | "0.9.0" | "0.10.0";
447
497
  /**
448
498
  * Which process observed this. Several instances of one deployment get the same order on purpose (ADR 0071), so the cloud has to be able to tell two answers apart.
449
499
  */
@@ -468,6 +518,7 @@ interface CaptureEvidence {
468
518
  */
469
519
  requests: CapturedRequest[];
470
520
  reference?: ReferenceSamples;
521
+ coarse?: CoarseSummary;
471
522
  }
472
523
  /**
473
524
  * `product.md:192` asks a capture to declare **both** coverages: what it attached from detail still retained, and what it observed from its effective start. Two numbers, never one — a total would hide that half of it is older than the capture.
@@ -489,6 +540,24 @@ interface CaptureCoverage {
489
540
  * Requests that ran more operations than the register keeps per request. Their count is real and their list is not complete.
490
541
  */
491
542
  truncated: number;
543
+ shed?: Shed;
544
+ /**
545
+ * Requests whose list of dependencies was truncated. Their count is real and their list is not complete. A sender that knows the field sends it, zero included. Absent in an evidence of protocol 0.9.0 or later is zero: @downtrace/agent 0.9.0 omitted it at zero. Absent in an earlier protocol is a sender older than the field, which did not say, and that is not none.
546
+ */
547
+ dependenciesTruncated?: number;
548
+ }
549
+ /**
550
+ * The time inside [startedAt, endedAt] when the instrumentation was not writing the fine detail — neither the register's ring nor the reserve — because it was shedding it. Present when some part of the window was shed, absent when there was no shedding, when the shedding came from configuration (`DOWNTRACE_SHED`, the benchmark) and so the instrumentation never decided it, or when the instrumentation predates the field: a sender older than the field sends nothing, and the cloud stores the absence as such (ADR 0008). The capture is still taken, not refused: the window can end before the shedding does, the coarse register keeps measuring, and the protocol has no way for an instance to refuse an order — saying it in the evidence is what CAP-01 asks for.
551
+ */
552
+ interface Shed {
553
+ /**
554
+ * How long the shedding lasted, in whole milliseconds, rounded up: one millisecond of shedding is still shedding, and the field says so rather than rounding it into silence.
555
+ */
556
+ ms: number;
557
+ /**
558
+ * The last reason in force inside the window, the same enum as `agent.resources.shedReason` in the batch: why it gave ground. One value and not a list: a window that shed for two reasons is read as the one in force when it ended, which is the one still changing what arrives.
559
+ */
560
+ reason: "latency" | "memory";
492
561
  }
493
562
  interface CapturedRequest {
494
563
  method: string;
@@ -520,11 +589,19 @@ interface CapturedRequest {
520
589
  * This request's operations were overwritten before they were read. Absent means false. Its timing is still true.
521
590
  */
522
591
  detailLost?: boolean;
592
+ /**
593
+ * This request's list of dependencies did not fit and was truncated to what the register keeps per request. A dependency not in the list is not proven not to have been used (invariant 14). Absent means false.
594
+ */
595
+ dependenciesTruncated?: boolean;
523
596
  }
524
597
  /**
525
598
  * One operation inside a request. Starts and ends and not durations, because the whole reason for capturing detail is order and overlap, which a duration cannot express (ADR 0068).
526
599
  */
527
600
  interface CapturedOperation {
601
+ /**
602
+ * What kind of operation this is, in the words of the batch's `Operation.kind`, whose enum this borrows: a query, an outgoing call or a Redis command the request ran, or one of the kinds of error recorded in it beside what failed. Since 0.9.0. **Absent means the sender did not say**, never a query: an instrumentation older than the field wrote every operation it recorded here without one, the error signatures beside a failed query among them, and a reader that took them for queries would be naming what it was not told.
603
+ */
604
+ kind?: "query" | "error" | "framework" | "explicit" | "call" | "command";
528
605
  /**
529
606
  * The fingerprint's hash. Never the text: the profile is where a sender chooses whether to ship the text of its queries, and this path never carries it (invariant 5, ADR 0017).
530
607
  */
@@ -536,7 +613,7 @@ interface CapturedOperation {
536
613
  endMs: number;
537
614
  }
538
615
  /**
539
- * A few requests of each endpoint kept as something to compare the captured ones against. `product.md:100`: «Comparar requests degradadas con requests de referencia exige conservar ambas; el detalle fino de hace una hora ya no existe». Being earlier does not certify health, which is why every field here is about how they were chosen and none of them says «healthy».
616
+ * A few requests of each endpoint kept as something to compare the captured ones against. `product.md:100`: «Comparing degraded requests against reference requests requires keeping both; the fine detail of an hour ago no longer exists». Being earlier does not certify health, which is why every field here is about how they were chosen and none of them says «healthy».
540
617
  */
541
618
  interface ReferenceSamples {
542
619
  /**
@@ -548,7 +625,7 @@ interface ReferenceSamples {
548
625
  */
549
626
  population: number;
550
627
  /**
551
- * Endpoints seen that the register had no room for. Counted rather than silently absent: an endpoint with no samples is not an endpoint with no traffic (invariant 14).
628
+ * Routes the register had no row for, folded into one shared row, counted once each. At the register's cap for how many it may remember it is a lower bound: a bounded memory does not count distinct names past its bound, and the volume of what was folded is what the shared row keeps.
552
629
  */
553
630
  routesDropped?: number;
554
631
  /**
@@ -562,6 +639,75 @@ interface ReferenceSamples {
562
639
  */
563
640
  samples: CapturedRequest[];
564
641
  }
642
+ /**
643
+ * The coarse half of the black box, frozen: the last few minutes, second by second, so a reader can see how something detected late began (`product.md:94`). Sums and a maximum, never percentiles: the interval aggregate answers the percentile question with exactness, and this answers the shape of the change (`product.md:122`). What an older instrumentation did not send is absent from the evidence, and stored as absent.
644
+ */
645
+ interface CoarseSummary {
646
+ /**
647
+ * How many seconds the summary covers: the length of the register's window, and the most any of the lists below may hold.
648
+ */
649
+ windowSeconds: number;
650
+ /**
651
+ * Routes the register had no row for, folded into one shared row, counted once each. At the register's cap for how many it may remember it is a lower bound: a bounded memory does not count distinct names past its bound, and the volume of what was folded is what the shared row keeps.
652
+ */
653
+ routesDropped: number;
654
+ /**
655
+ * One entry per route with a row of its own, the last being the shared row for what did not fit, when there is one. A route's series starts at the first second this process saw the route: before it, nobody was watching this route, and inventing silence there would say the route was quiet when the truth is that it was unwatched (invariant 14).
656
+ *
657
+ * @maxItems 129
658
+ */
659
+ routes: CoarseRoute[];
660
+ /**
661
+ * The process's event loop delay, second by second, in its own series and not attributed to any route: it is the process's, and attributing it to a route would be inventing a measurement. Only the seconds somebody sampled are here: a second with no reading says nothing about the loop, and a zero would say it was idle. An empty array is a real answer: the process had no event loop to sample, or nobody did.
662
+ *
663
+ * @maxItems 300
664
+ */
665
+ eventLoop: CoarseEventLoopSecond[];
666
+ }
667
+ interface CoarseRoute {
668
+ method: string;
669
+ /**
670
+ * The route template, never the path with its values in it (invariant 5).
671
+ */
672
+ route: string;
673
+ /**
674
+ * @maxItems 300
675
+ */
676
+ seconds: CoarseSecond[];
677
+ }
678
+ /**
679
+ * One second of one route. Sums and a maximum, never a histogram: a histogram per second per route would multiply the memory by its buckets to answer a question the interval already answers.
680
+ */
681
+ interface CoarseSecond {
682
+ /**
683
+ * The Unix second this row covers, an integer instant like the ones a batch writes: a reader aligns it with the dates the evidence writes by flooring them.
684
+ */
685
+ second: number;
686
+ /**
687
+ * Requests this route answered in this second. Zero is a real answer: a watched second with no traffic, and not an absence.
688
+ */
689
+ requests: number;
690
+ /**
691
+ * Requests that answered 5xx.
692
+ */
693
+ errors: number;
694
+ latencySumMs: number;
695
+ latencyMaxMs: number;
696
+ /**
697
+ * Operations the requests of this second ran.
698
+ */
699
+ calls: number;
700
+ }
701
+ interface CoarseEventLoopSecond {
702
+ /**
703
+ * The Unix second this reading covers.
704
+ */
705
+ second: number;
706
+ /**
707
+ * The worst delay sampled in this second: a second that stalled once stalled, and averaging it away is how a stall becomes invisible.
708
+ */
709
+ maxDelayMs: number;
710
+ }
565
711
  //#endregion
566
712
  //#region src/generated/ingest-response.d.ts
567
713
  /**
@@ -620,9 +766,9 @@ interface PendingCapture {
620
766
  //#endregion
621
767
  //#region src/generated/versions.d.ts
622
768
  /** Every published minor of v0, oldest first. The cloud never stops accepting one it published (ADR 0008). */
623
- declare const ACCEPTED_PROTOCOL_VERSIONS_V0: readonly ["0.1.0", "0.2.0", "0.3.0", "0.4.0", "0.5.0", "0.6.0", "0.7.0", "0.8.0"];
769
+ declare const ACCEPTED_PROTOCOL_VERSIONS_V0: readonly ["0.1.0", "0.2.0", "0.3.0", "0.4.0", "0.5.0", "0.6.0", "0.7.0", "0.8.0", "0.9.0", "0.10.0"];
624
770
  /** The newest published minor: what an up-to-date agent stamps on every batch. */
625
- declare const PROTOCOL_VERSION = "0.8.0";
771
+ declare const PROTOCOL_VERSION = "0.10.0";
626
772
  //#endregion
627
773
  //#region src/index.d.ts
628
774
  /** The JSON Schema (draft 2020-12) for AggregatesBatch, for validators on either side. */
@@ -686,6 +832,10 @@ declare const AGGREGATES_SCHEMA_V0: {
686
832
  };
687
833
  description: string;
688
834
  };
835
+ ending: {
836
+ enum: string[];
837
+ description: string;
838
+ };
689
839
  };
690
840
  $defs: {
691
841
  AgentInfo: {
@@ -724,8 +874,48 @@ declare const AGGREGATES_SCHEMA_V0: {
724
874
  $ref: string;
725
875
  description: string;
726
876
  };
877
+ errorSources: {
878
+ $ref: string;
879
+ description: string;
880
+ };
881
+ };
882
+ };
883
+ ErrorSources: {
884
+ title: string;
885
+ type: string;
886
+ additionalProperties: boolean;
887
+ required: string[];
888
+ properties: {
889
+ inRequest: {
890
+ type: string;
891
+ uniqueItems: boolean;
892
+ items: {
893
+ $ref: string;
894
+ };
895
+ description: string;
896
+ };
897
+ outsideRequest: {
898
+ type: string;
899
+ uniqueItems: boolean;
900
+ items: {
901
+ $ref: string;
902
+ };
903
+ description: string;
904
+ };
727
905
  };
728
906
  };
907
+ InRequestErrorSource: {
908
+ title: string;
909
+ type: string;
910
+ enum: string[];
911
+ description: string;
912
+ };
913
+ OutsideRequestErrorSource: {
914
+ title: string;
915
+ type: string;
916
+ enum: string[];
917
+ description: string;
918
+ };
729
919
  InstanceInfo: {
730
920
  title: string;
731
921
  type: string;
@@ -1086,6 +1276,22 @@ declare const AGGREGATES_SCHEMA_V0: {
1086
1276
  properties: {
1087
1277
  kind: {
1088
1278
  enum: string[];
1279
+ "x-since": {
1280
+ query: string;
1281
+ error: string;
1282
+ framework: string;
1283
+ explicit: string;
1284
+ call: string;
1285
+ command: string;
1286
+ };
1287
+ "x-error": {
1288
+ query: boolean;
1289
+ error: boolean;
1290
+ framework: boolean;
1291
+ explicit: boolean;
1292
+ call: boolean;
1293
+ command: boolean;
1294
+ };
1089
1295
  description: string;
1090
1296
  };
1091
1297
  hash: {
@@ -1119,6 +1325,9 @@ declare const AGGREGATES_SCHEMA_V0: {
1119
1325
  minimum: number;
1120
1326
  description: string;
1121
1327
  };
1328
+ context: {
1329
+ $ref: string;
1330
+ };
1122
1331
  class: {
1123
1332
  enum: string[];
1124
1333
  description: string;
@@ -1131,6 +1340,21 @@ declare const AGGREGATES_SCHEMA_V0: {
1131
1340
  text: {};
1132
1341
  };
1133
1342
  };
1343
+ if: {
1344
+ properties: {
1345
+ kind: {
1346
+ enum: string[];
1347
+ };
1348
+ };
1349
+ };
1350
+ then: {
1351
+ properties: {
1352
+ text: {
1353
+ type: string;
1354
+ pattern: string;
1355
+ };
1356
+ };
1357
+ };
1134
1358
  };
1135
1359
  ObserverState: {
1136
1360
  title: string;
@@ -1209,6 +1433,12 @@ declare const AGGREGATES_SCHEMA_V0: {
1209
1433
  properties: {
1210
1434
  kind: {
1211
1435
  enum: string[];
1436
+ "x-since": {
1437
+ uncaught: string;
1438
+ "unhandled-rejection": string;
1439
+ framework: string;
1440
+ explicit: string;
1441
+ };
1212
1442
  description: string;
1213
1443
  };
1214
1444
  hash: {
@@ -1227,7 +1457,28 @@ declare const AGGREGATES_SCHEMA_V0: {
1227
1457
  minimum: number;
1228
1458
  description: string;
1229
1459
  };
1460
+ total: {
1461
+ type: string;
1462
+ minimum: number;
1463
+ description: string;
1464
+ };
1465
+ context: {
1466
+ $ref: string;
1467
+ };
1468
+ };
1469
+ };
1470
+ ReportedContext: {
1471
+ title: string;
1472
+ type: string;
1473
+ maxProperties: number;
1474
+ propertyNames: {
1475
+ maxLength: number;
1230
1476
  };
1477
+ additionalProperties: {
1478
+ type: string;
1479
+ maxLength: number;
1480
+ };
1481
+ description: string;
1231
1482
  };
1232
1483
  LocalTrigger: {
1233
1484
  type: string;
@@ -1289,6 +1540,11 @@ declare const AGGREGATES_SCHEMA_V0: {
1289
1540
  minimum: number;
1290
1541
  description: string;
1291
1542
  };
1543
+ droppedExceptions: {
1544
+ type: string;
1545
+ minimum: number;
1546
+ description: string;
1547
+ };
1292
1548
  bufferBytes: {
1293
1549
  type: string;
1294
1550
  minimum: number;
@@ -1463,6 +1719,9 @@ declare const CAPTURE_EVIDENCE_SCHEMA_V0: {
1463
1719
  reference: {
1464
1720
  $ref: string;
1465
1721
  };
1722
+ coarse: {
1723
+ $ref: string;
1724
+ };
1466
1725
  };
1467
1726
  $defs: {
1468
1727
  Coverage: {
@@ -1492,6 +1751,33 @@ declare const CAPTURE_EVIDENCE_SCHEMA_V0: {
1492
1751
  minimum: number;
1493
1752
  description: string;
1494
1753
  };
1754
+ shed: {
1755
+ $ref: string;
1756
+ };
1757
+ dependenciesTruncated: {
1758
+ type: string;
1759
+ minimum: number;
1760
+ description: string;
1761
+ };
1762
+ };
1763
+ };
1764
+ Shed: {
1765
+ type: string;
1766
+ title: string;
1767
+ additionalProperties: boolean;
1768
+ required: string[];
1769
+ description: string;
1770
+ properties: {
1771
+ ms: {
1772
+ type: string;
1773
+ minimum: number;
1774
+ description: string;
1775
+ };
1776
+ reason: {
1777
+ type: string;
1778
+ enum: string[];
1779
+ description: string;
1780
+ };
1495
1781
  };
1496
1782
  };
1497
1783
  CapturedRequest: {
@@ -1544,6 +1830,10 @@ declare const CAPTURE_EVIDENCE_SCHEMA_V0: {
1544
1830
  type: string;
1545
1831
  description: string;
1546
1832
  };
1833
+ dependenciesTruncated: {
1834
+ type: string;
1835
+ description: string;
1836
+ };
1547
1837
  };
1548
1838
  };
1549
1839
  CapturedOperation: {
@@ -1553,6 +1843,10 @@ declare const CAPTURE_EVIDENCE_SCHEMA_V0: {
1553
1843
  required: string[];
1554
1844
  description: string;
1555
1845
  properties: {
1846
+ kind: {
1847
+ enum: string[];
1848
+ description: string;
1849
+ };
1556
1850
  hash: {
1557
1851
  type: string;
1558
1852
  minLength: number;
@@ -1606,6 +1900,118 @@ declare const CAPTURE_EVIDENCE_SCHEMA_V0: {
1606
1900
  };
1607
1901
  };
1608
1902
  };
1903
+ CoarseSummary: {
1904
+ type: string;
1905
+ title: string;
1906
+ additionalProperties: boolean;
1907
+ required: string[];
1908
+ description: string;
1909
+ properties: {
1910
+ windowSeconds: {
1911
+ type: string;
1912
+ minimum: number;
1913
+ description: string;
1914
+ };
1915
+ routesDropped: {
1916
+ type: string;
1917
+ minimum: number;
1918
+ description: string;
1919
+ };
1920
+ routes: {
1921
+ type: string;
1922
+ maxItems: number;
1923
+ items: {
1924
+ $ref: string;
1925
+ };
1926
+ description: string;
1927
+ };
1928
+ eventLoop: {
1929
+ type: string;
1930
+ maxItems: number;
1931
+ items: {
1932
+ $ref: string;
1933
+ };
1934
+ description: string;
1935
+ };
1936
+ };
1937
+ };
1938
+ CoarseRoute: {
1939
+ type: string;
1940
+ title: string;
1941
+ additionalProperties: boolean;
1942
+ required: string[];
1943
+ properties: {
1944
+ method: {
1945
+ type: string;
1946
+ maxLength: number;
1947
+ };
1948
+ route: {
1949
+ type: string;
1950
+ maxLength: number;
1951
+ description: string;
1952
+ };
1953
+ seconds: {
1954
+ type: string;
1955
+ maxItems: number;
1956
+ items: {
1957
+ $ref: string;
1958
+ };
1959
+ };
1960
+ };
1961
+ };
1962
+ CoarseSecond: {
1963
+ type: string;
1964
+ title: string;
1965
+ additionalProperties: boolean;
1966
+ required: string[];
1967
+ description: string;
1968
+ properties: {
1969
+ second: {
1970
+ type: string;
1971
+ description: string;
1972
+ };
1973
+ requests: {
1974
+ type: string;
1975
+ minimum: number;
1976
+ description: string;
1977
+ };
1978
+ errors: {
1979
+ type: string;
1980
+ minimum: number;
1981
+ description: string;
1982
+ };
1983
+ latencySumMs: {
1984
+ type: string;
1985
+ minimum: number;
1986
+ };
1987
+ latencyMaxMs: {
1988
+ type: string;
1989
+ minimum: number;
1990
+ };
1991
+ calls: {
1992
+ type: string;
1993
+ minimum: number;
1994
+ description: string;
1995
+ };
1996
+ };
1997
+ };
1998
+ CoarseEventLoopSecond: {
1999
+ type: string;
2000
+ title: string;
2001
+ additionalProperties: boolean;
2002
+ required: string[];
2003
+ properties: {
2004
+ second: {
2005
+ type: string;
2006
+ description: string;
2007
+ };
2008
+ maxDelayMs: {
2009
+ type: string;
2010
+ minimum: number;
2011
+ description: string;
2012
+ };
2013
+ };
2014
+ };
1609
2015
  };
1610
2016
  };
1611
2017
  /** Index of the bucket a latency (ms) falls into: first boundary >= latency, else the open-ended last bucket. */
@@ -1613,4 +2019,4 @@ declare function latencyBucket(ms: number): number;
1613
2019
  /** Index of the bucket a call count falls into: first boundary >= count, else the open-ended last bucket. */
1614
2020
  declare function callsPerRequestBucket(calls: number): number;
1615
2021
  //#endregion
1616
- export { ACCEPTED_PROTOCOL_VERSIONS_V0, AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, type AgentInfo, type AgentResources, type AggregatesBatch, CALLS_PER_REQUEST_BOUNDARIES_V0, CALLS_PER_REQUEST_BUCKETS_V0, CAPTURE_EVIDENCE_PATH, CAPTURE_EVIDENCE_SCHEMA_V0, type CaptureCoverage, type CaptureEvidence, type CaptureProgress, type CapturedOperation, type CapturedRequest, type Dependency, type DeployInfo, type Endpoint, INGEST_RESPONSE_SCHEMA_V0, type IngestResponse, type InstanceInfo, type Interval, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, type LatencyHistogram, type LocalTrigger, type ObserverState, type Observers, type Operation, PROTOCOL_VERSION, type PendingCapture, type PostgresStats, type Profile, type ProfileEndpoint, type RuntimeHealth, type StatusClasses, callsPerRequestBucket, captureEvidencePath, latencyBucket };
2022
+ export { ACCEPTED_PROTOCOL_VERSIONS_V0, AGGREGATES_PATH, AGGREGATES_SCHEMA_V0, type AgentInfo, type AgentResources, type AggregatesBatch, CALLS_PER_REQUEST_BOUNDARIES_V0, CALLS_PER_REQUEST_BUCKETS_V0, CAPTURE_EVIDENCE_PATH, CAPTURE_EVIDENCE_SCHEMA_V0, type CaptureCoverage, type CaptureEvidence, type CaptureProgress, type CapturedOperation, type CapturedRequest, DEPENDENCIES_MAX_ITEMS_V0, DEPENDENCY_KINDS_V0, type Dependency, type DeployInfo, EVIDENCE_REQUESTS_MAX_ITEMS_V0, type Endpoint, INGEST_RESPONSE_SCHEMA_V0, type IngestResponse, type InstanceInfo, type Interval, LATENCY_BOUNDARIES_V0, LATENCY_BUCKETS_V0, type LatencyHistogram, type LocalTrigger, type ObserverState, type Observers, type Operation, PROTOCOL_VERSION, type PendingCapture, type PostgresStats, type Profile, type ProfileEndpoint, type RuntimeHealth, type StatusClasses, callsPerRequestBucket, captureEvidencePath, latencyBucket };