@uptimizr/db 2.0.1 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +228 -3
- package/README.md +13 -0
- package/dist/duckdb/migrations.d.ts.map +1 -1
- package/dist/duckdb/migrations.js +169 -0
- package/dist/duckdb/migrations.js.map +1 -1
- package/dist/duckdb/panelSpecs.d.ts +29 -0
- package/dist/duckdb/panelSpecs.d.ts.map +1 -0
- package/dist/duckdb/panelSpecs.js +104 -0
- package/dist/duckdb/panelSpecs.js.map +1 -0
- package/dist/duckdb/projectMetadata.d.ts +43 -0
- package/dist/duckdb/projectMetadata.d.ts.map +1 -0
- package/dist/duckdb/projectMetadata.js +222 -0
- package/dist/duckdb/projectMetadata.js.map +1 -0
- package/dist/duckdb/subscriptions.d.ts +45 -0
- package/dist/duckdb/subscriptions.d.ts.map +1 -0
- package/dist/duckdb/subscriptions.js +202 -0
- package/dist/duckdb/subscriptions.js.map +1 -0
- package/dist/index.d.ts +18 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +48 -3
- package/dist/index.js.map +1 -1
- package/dist/insights/anomalies.d.ts +213 -0
- package/dist/insights/anomalies.d.ts.map +1 -0
- package/dist/insights/anomalies.js +340 -0
- package/dist/insights/anomalies.js.map +1 -0
- package/dist/insights/baseline.d.ts +51 -0
- package/dist/insights/baseline.d.ts.map +1 -0
- package/dist/insights/baseline.js +48 -0
- package/dist/insights/baseline.js.map +1 -0
- package/dist/insights/buckets.d.ts +114 -0
- package/dist/insights/buckets.d.ts.map +1 -0
- package/dist/insights/buckets.js +220 -0
- package/dist/insights/buckets.js.map +1 -0
- package/dist/insights/changepoint.d.ts +130 -0
- package/dist/insights/changepoint.d.ts.map +1 -0
- package/dist/insights/changepoint.js +209 -0
- package/dist/insights/changepoint.js.map +1 -0
- package/dist/insights/evaluate.d.ts +63 -0
- package/dist/insights/evaluate.d.ts.map +1 -0
- package/dist/insights/evaluate.js +158 -0
- package/dist/insights/evaluate.js.map +1 -0
- package/dist/insights/health.d.ts +219 -0
- package/dist/insights/health.d.ts.map +1 -0
- package/dist/insights/health.js +349 -0
- package/dist/insights/health.js.map +1 -0
- package/dist/insights/index.d.ts +45 -0
- package/dist/insights/index.d.ts.map +1 -0
- package/dist/insights/index.js +40 -0
- package/dist/insights/index.js.map +1 -0
- package/dist/insights/measures.d.ts +222 -0
- package/dist/insights/measures.d.ts.map +1 -0
- package/dist/insights/measures.js +431 -0
- package/dist/insights/measures.js.map +1 -0
- package/dist/insights/movers.d.ts +123 -0
- package/dist/insights/movers.d.ts.map +1 -0
- package/dist/insights/movers.js +166 -0
- package/dist/insights/movers.js.map +1 -0
- package/dist/insights/significance.d.ts +221 -0
- package/dist/insights/significance.d.ts.map +1 -0
- package/dist/insights/significance.js +531 -0
- package/dist/insights/significance.js.map +1 -0
- package/dist/insights/stats.d.ts +104 -0
- package/dist/insights/stats.d.ts.map +1 -0
- package/dist/insights/stats.js +181 -0
- package/dist/insights/stats.js.map +1 -0
- package/dist/insights/windows.d.ts +95 -0
- package/dist/insights/windows.d.ts.map +1 -0
- package/dist/insights/windows.js +97 -0
- package/dist/insights/windows.js.map +1 -0
- package/dist/metadata.d.ts +178 -1
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +80 -0
- package/dist/metadata.js.map +1 -1
- package/dist/narrative/build.d.ts +78 -0
- package/dist/narrative/build.d.ts.map +1 -0
- package/dist/narrative/build.js +437 -0
- package/dist/narrative/build.js.map +1 -0
- package/dist/narrative/index.d.ts +14 -0
- package/dist/narrative/index.d.ts.map +1 -0
- package/dist/narrative/index.js +13 -0
- package/dist/narrative/index.js.map +1 -0
- package/dist/narrative/text.d.ts +25 -0
- package/dist/narrative/text.d.ts.map +1 -0
- package/dist/narrative/text.js +41 -0
- package/dist/narrative/text.js.map +1 -0
- package/dist/parity/cases.d.ts +3 -0
- package/dist/parity/cases.d.ts.map +1 -1
- package/dist/parity/cases.js +387 -7
- package/dist/parity/cases.js.map +1 -1
- package/dist/parity/compare.d.ts +19 -0
- package/dist/parity/compare.d.ts.map +1 -1
- package/dist/parity/compare.js +19 -0
- package/dist/parity/compare.js.map +1 -1
- package/dist/parity/fixtures.d.ts.map +1 -1
- package/dist/parity/fixtures.js +25 -0
- package/dist/parity/fixtures.js.map +1 -1
- package/dist/query/aggregations.d.ts +46 -1
- package/dist/query/aggregations.d.ts.map +1 -1
- package/dist/query/aggregations.js +86 -0
- package/dist/query/aggregations.js.map +1 -1
- package/dist/query/clickhouseDialect.d.ts.map +1 -1
- package/dist/query/clickhouseDialect.js +5 -1
- package/dist/query/clickhouseDialect.js.map +1 -1
- package/dist/query/customEventVocabulary.d.ts +46 -0
- package/dist/query/customEventVocabulary.d.ts.map +1 -0
- package/dist/query/customEventVocabulary.js +127 -0
- package/dist/query/customEventVocabulary.js.map +1 -0
- package/dist/query/dsl/builders.d.ts +38 -0
- package/dist/query/dsl/builders.d.ts.map +1 -0
- package/dist/query/dsl/builders.js +35 -0
- package/dist/query/dsl/builders.js.map +1 -0
- package/dist/query/dsl/compare.d.ts +167 -0
- package/dist/query/dsl/compare.d.ts.map +1 -0
- package/dist/query/dsl/compare.js +358 -0
- package/dist/query/dsl/compare.js.map +1 -0
- package/dist/query/dsl/compile.d.ts +89 -0
- package/dist/query/dsl/compile.d.ts.map +1 -0
- package/dist/query/dsl/compile.js +174 -0
- package/dist/query/dsl/compile.js.map +1 -0
- package/dist/query/dsl/explain.d.ts +115 -0
- package/dist/query/dsl/explain.d.ts.map +1 -0
- package/dist/query/dsl/explain.js +143 -0
- package/dist/query/dsl/explain.js.map +1 -0
- package/dist/query/dsl/generic.d.ts +127 -0
- package/dist/query/dsl/generic.d.ts.map +1 -0
- package/dist/query/dsl/generic.js +323 -0
- package/dist/query/dsl/generic.js.map +1 -0
- package/dist/query/dsl/index.d.ts +30 -0
- package/dist/query/dsl/index.d.ts.map +1 -0
- package/dist/query/dsl/index.js +23 -0
- package/dist/query/dsl/index.js.map +1 -0
- package/dist/query/dsl/order.d.ts +41 -0
- package/dist/query/dsl/order.d.ts.map +1 -0
- package/dist/query/dsl/order.js +55 -0
- package/dist/query/dsl/order.js.map +1 -0
- package/dist/query/dsl/significance.d.ts +130 -0
- package/dist/query/dsl/significance.d.ts.map +1 -0
- package/dist/query/dsl/significance.js +224 -0
- package/dist/query/dsl/significance.js.map +1 -0
- package/dist/query/index.d.ts +2 -0
- package/dist/query/index.d.ts.map +1 -1
- package/dist/query/index.js +8 -0
- package/dist/query/index.js.map +1 -1
- package/dist/query/summary/index.d.ts +4 -2
- package/dist/query/summary/index.d.ts.map +1 -1
- package/dist/query/summary/index.js +2 -1
- package/dist/query/summary/index.js.map +1 -1
- package/dist/query/summary/labels.d.ts +101 -0
- package/dist/query/summary/labels.d.ts.map +1 -0
- package/dist/query/summary/labels.js +261 -0
- package/dist/query/summary/labels.js.map +1 -0
- package/dist/query/summary/reading.d.ts.map +1 -1
- package/dist/query/summary/reading.js +21 -2
- package/dist/query/summary/reading.js.map +1 -1
- package/dist/query/summary/schema.d.ts +250 -20
- package/dist/query/summary/schema.d.ts.map +1 -1
- package/dist/query/summary/schema.js +135 -123
- package/dist/query/summary/schema.js.map +1 -1
- package/dist/query/summary/summarize.d.ts.map +1 -1
- package/dist/query/summary/summarize.js +91 -5
- package/dist/query/summary/summarize.js.map +1 -1
- package/dist/query/summary/types.d.ts +77 -2
- package/dist/query/summary/types.d.ts.map +1 -1
- package/dist/query/types.d.ts +47 -1
- package/dist/query/types.d.ts.map +1 -1
- package/dist/subscriptions.d.ts +208 -0
- package/dist/subscriptions.d.ts.map +1 -0
- package/dist/subscriptions.js +153 -0
- package/dist/subscriptions.js.map +1 -0
- package/llms.txt +9 -0
- package/package.json +8 -8
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The in-memory evaluator for a {@link BucketMeasure} (ADR 0051 §4).
|
|
3
|
+
*
|
|
4
|
+
* `buildMetricBuckets` renders a measure to SQL for the four persistent stores.
|
|
5
|
+
* The collector also ships an in-memory store — the one the playground and the
|
|
6
|
+
* end-to-end harness boot without a database — which has no SQL to run. Rather
|
|
7
|
+
* than let the insight endpoints go dark there (an empty series reads as "no
|
|
8
|
+
* data", which is a different and misleading claim), the same declarative
|
|
9
|
+
* measure is evaluated directly over events here.
|
|
10
|
+
*
|
|
11
|
+
* Pure, and deliberately the *same shape* as the SQL: one pass that groups by
|
|
12
|
+
* bucket, then one aggregate per bucket, using the same closed predicate
|
|
13
|
+
* vocabulary. `src/__tests__/insights.test.ts` runs both paths over the same
|
|
14
|
+
* rows so the two cannot drift.
|
|
15
|
+
*/
|
|
16
|
+
import { resolveBucketMeasure, BUCKET_SECONDS, } from "./measures.js";
|
|
17
|
+
import { byBucketThenDimension } from "./buckets.js";
|
|
18
|
+
import { quantile } from "./stats.js";
|
|
19
|
+
/** The vector columns a geometry predicate can guard. */
|
|
20
|
+
const VECTORS = ["position", "direction", "hit_point", "screen"];
|
|
21
|
+
/**
|
|
22
|
+
* The split dimension's value on one event — the in-memory mirror of
|
|
23
|
+
* `BUCKET_SPLIT_COLUMNS` (#306). `''` is "unknown", the same reading the stores'
|
|
24
|
+
* `NOT NULL DEFAULT ''` columns give.
|
|
25
|
+
*/
|
|
26
|
+
function splitValueOf(event, dimension) {
|
|
27
|
+
switch (dimension) {
|
|
28
|
+
case "scene":
|
|
29
|
+
return event.scene_id ?? "";
|
|
30
|
+
case "event_type":
|
|
31
|
+
return event.event_type ?? "";
|
|
32
|
+
case "mesh":
|
|
33
|
+
return event.mesh ?? "";
|
|
34
|
+
case "name":
|
|
35
|
+
return event.name ?? "";
|
|
36
|
+
case "source":
|
|
37
|
+
return event.source ?? "";
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/** Whether an event satisfies one predicate from the closed vocabulary. */
|
|
41
|
+
function matches(event, predicate) {
|
|
42
|
+
switch (predicate.kind) {
|
|
43
|
+
case "eq":
|
|
44
|
+
return (event[predicate.column] ?? "") === predicate.value;
|
|
45
|
+
case "ne":
|
|
46
|
+
return (event[predicate.column] ?? "") !== predicate.value;
|
|
47
|
+
case "in":
|
|
48
|
+
return predicate.values.includes(event[predicate.column] ?? "");
|
|
49
|
+
case "geometry": {
|
|
50
|
+
const column = VECTORS.find((name) => name === predicate.column);
|
|
51
|
+
const vector = column == null ? undefined : event[column];
|
|
52
|
+
return Array.isArray(vector) && vector.length === predicate.arity;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
/** The numeric value a measure's aggregate reads off one event. */
|
|
57
|
+
function valueOf(event, measure) {
|
|
58
|
+
if (measure.aggregate.kind === "count" || measure.aggregate.kind === "sessions")
|
|
59
|
+
return null;
|
|
60
|
+
const raw = event[measure.aggregate.column];
|
|
61
|
+
if (typeof raw !== "number" || !Number.isFinite(raw))
|
|
62
|
+
return null;
|
|
63
|
+
// `js_heap_bytes` of 0 means "not reported" — excluded from averages and
|
|
64
|
+
// percentiles, kept for a max. Mirrors `valueColumnExpr` in `buckets.ts`.
|
|
65
|
+
if (measure.aggregate.column === "js_heap_bytes" &&
|
|
66
|
+
raw === 0 &&
|
|
67
|
+
measure.aggregate.kind !== "max") {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
return raw;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Evaluate a metric's bucket series over events held in memory.
|
|
74
|
+
*
|
|
75
|
+
* Returns the same rows `buildMetricBuckets` would: ascending by bucket, with
|
|
76
|
+
* buckets that matched nothing simply absent. Throws for a metric with no
|
|
77
|
+
* portable bucket form, exactly as the builder does.
|
|
78
|
+
*/
|
|
79
|
+
export function evaluateBucketMeasure(events, opts) {
|
|
80
|
+
const measure = resolveBucketMeasure(opts.metric, opts.series);
|
|
81
|
+
if (measure == null) {
|
|
82
|
+
throw new Error(opts.series == null
|
|
83
|
+
? `metric '${opts.metric}' has no portable bucket series`
|
|
84
|
+
: `metric '${opts.metric}' declares no '${opts.series}' series`);
|
|
85
|
+
}
|
|
86
|
+
const width = BUCKET_SECONDS[opts.bucket ?? "day"] * 1000;
|
|
87
|
+
const types = measure.eventTypes.length > 0 ? new Set(measure.eventTypes) : null;
|
|
88
|
+
// Keyed by bucket, or by `bucket|dimension` on a grouped read (#306) — the
|
|
89
|
+
// in-memory counterpart of adding the column to the SQL `GROUP BY`.
|
|
90
|
+
const buckets = new Map();
|
|
91
|
+
for (const event of events) {
|
|
92
|
+
if (!Number.isFinite(event.ts))
|
|
93
|
+
continue;
|
|
94
|
+
if (opts.since != null && event.ts < opts.since)
|
|
95
|
+
continue;
|
|
96
|
+
if (opts.until != null && event.ts >= opts.until)
|
|
97
|
+
continue;
|
|
98
|
+
if (opts.scene != null && opts.scene.length > 0 && event.scene_id !== opts.scene)
|
|
99
|
+
continue;
|
|
100
|
+
if (types != null && !types.has(event.event_type))
|
|
101
|
+
continue;
|
|
102
|
+
if ((measure.where ?? []).some((predicate) => !matches(event, predicate)))
|
|
103
|
+
continue;
|
|
104
|
+
const start = Math.floor(event.ts / width) * width;
|
|
105
|
+
const dimension = opts.groupBy == null ? null : splitValueOf(event, opts.groupBy);
|
|
106
|
+
const key = dimension == null ? String(start) : `${start}|${dimension}`;
|
|
107
|
+
let entry = buckets.get(key);
|
|
108
|
+
if (entry == null) {
|
|
109
|
+
entry = { start, dimension, values: [], count: 0, sessions: new Set() };
|
|
110
|
+
buckets.set(key, entry);
|
|
111
|
+
}
|
|
112
|
+
entry.count += 1;
|
|
113
|
+
entry.sessions.add(event.session_id);
|
|
114
|
+
const value = valueOf(event, measure);
|
|
115
|
+
if (value != null)
|
|
116
|
+
entry.values.push(value);
|
|
117
|
+
}
|
|
118
|
+
const rows = [];
|
|
119
|
+
for (const entry of buckets.values()) {
|
|
120
|
+
rows.push({
|
|
121
|
+
bucket: entry.start,
|
|
122
|
+
value: aggregate(entry, measure),
|
|
123
|
+
sample_size: measure.aggregate.kind === "sessions" ? entry.sessions.size : entry.count,
|
|
124
|
+
...(entry.dimension == null ? {} : { dimension_value: entry.dimension }),
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return rows.sort(byBucketThenDimension);
|
|
128
|
+
}
|
|
129
|
+
/** Apply a measure's aggregate to one bucket's accumulated values. */
|
|
130
|
+
function aggregate(entry, measure) {
|
|
131
|
+
switch (measure.aggregate.kind) {
|
|
132
|
+
case "count":
|
|
133
|
+
return entry.count;
|
|
134
|
+
case "sessions":
|
|
135
|
+
return entry.sessions.size;
|
|
136
|
+
case "sum": {
|
|
137
|
+
if (entry.values.length === 0)
|
|
138
|
+
return null;
|
|
139
|
+
let total = 0;
|
|
140
|
+
for (const value of entry.values)
|
|
141
|
+
total += value;
|
|
142
|
+
return total;
|
|
143
|
+
}
|
|
144
|
+
case "avg": {
|
|
145
|
+
if (entry.values.length === 0)
|
|
146
|
+
return null;
|
|
147
|
+
let total = 0;
|
|
148
|
+
for (const value of entry.values)
|
|
149
|
+
total += value;
|
|
150
|
+
return total / entry.values.length;
|
|
151
|
+
}
|
|
152
|
+
case "max":
|
|
153
|
+
return entry.values.length === 0 ? null : Math.max(...entry.values);
|
|
154
|
+
case "quantile":
|
|
155
|
+
return quantile(entry.values, measure.aggregate.q);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=evaluate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"evaluate.js","sourceRoot":"","sources":["../../src/insights/evaluate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* **`scene_health`** — "which scene is in trouble, and why?" (ADR 0051 §4, sketch §D).
|
|
3
|
+
*
|
|
4
|
+
* One number per scene, and — more importantly — the six numbers it was built
|
|
5
|
+
* from. A single score is only useful if it can be taken apart: every factor
|
|
6
|
+
* reports the **metric id** behind it, the **raw** value that metric produced,
|
|
7
|
+
* the **normalised** 0–100 it contributed and the **weight** it carried, so
|
|
8
|
+
* "the lobby is at 38" is always one step away from "because its 5th-percentile
|
|
9
|
+
* FPS is 19 against a project norm of 47".
|
|
10
|
+
*
|
|
11
|
+
* Pure TypeScript over the same bucket series as every other primitive.
|
|
12
|
+
*
|
|
13
|
+
* ## The score is relative, and says so
|
|
14
|
+
*
|
|
15
|
+
* There is no absolute scale on which 60 FPS is "healthy" — a marketing
|
|
16
|
+
* configurator and a six-player VR game do not share one — so every factor is
|
|
17
|
+
* normalised against **the project's own baseline over the previous equal
|
|
18
|
+
* window**, using the same robust centre-and-spread `movers` ranks with
|
|
19
|
+
* (median, and a MAD floored at 1% of the level). A factor exactly at the
|
|
20
|
+
* project norm scores **50**; {@link HEALTH_Z_SPAN} robust deviations better
|
|
21
|
+
* scores 100, the same distance worse scores 0.
|
|
22
|
+
*
|
|
23
|
+
* That makes the score a comparison, not a grade: a project where every scene
|
|
24
|
+
* is equally bad reads 50 across the board. It is the right shape for the
|
|
25
|
+
* question actually asked ("*which* scene should I look at this week"), and the
|
|
26
|
+
* registry entry's caveats say plainly that it is not a quality bar.
|
|
27
|
+
*
|
|
28
|
+
* ## Factors are declared, not inferred
|
|
29
|
+
*
|
|
30
|
+
* {@link HEALTH_FACTORS} is a fixed, ordered catalog. Each entry names the
|
|
31
|
+
* metric it reads, whether it is a level or a rate (and which catalog series
|
|
32
|
+
* supply the numerator and denominator), which direction is good, and its
|
|
33
|
+
* default weight. Nothing here is derived from a request, so the fan-out is a
|
|
34
|
+
* compile-time constant and a caller can only change the **weights** — never
|
|
35
|
+
* which series are read.
|
|
36
|
+
*/
|
|
37
|
+
import type { MetricId } from "@uptimizr/metrics";
|
|
38
|
+
import type { MetricBucketRow } from "./buckets.js";
|
|
39
|
+
import { type BucketGrain, type BucketVariant } from "./measures.js";
|
|
40
|
+
import { type ResolvedWindow } from "./windows.js";
|
|
41
|
+
/** How one health factor is measured. */
|
|
42
|
+
export interface HealthFactorSpec {
|
|
43
|
+
/** Stable factor id — the key a `weights` override addresses it by. */
|
|
44
|
+
readonly id: string;
|
|
45
|
+
/** The registry metric this factor is a reading of. */
|
|
46
|
+
readonly metric: MetricId;
|
|
47
|
+
/**
|
|
48
|
+
* The series that supplies the factor's numerator: a named catalog variant,
|
|
49
|
+
* or `undefined` for the metric's own headline series.
|
|
50
|
+
*/
|
|
51
|
+
readonly numerator?: BucketVariant;
|
|
52
|
+
/**
|
|
53
|
+
* The series that supplies the denominator, making this factor a **rate**.
|
|
54
|
+
* `undefined` for a level factor (an FPS percentile), which is read directly.
|
|
55
|
+
*/
|
|
56
|
+
readonly denominator?: BucketVariant;
|
|
57
|
+
/** Whether a *higher* raw value is healthier. */
|
|
58
|
+
readonly direction: "up" | "down";
|
|
59
|
+
/** Default weight in the score. Overridable per request. */
|
|
60
|
+
readonly weight: number;
|
|
61
|
+
/** What one unit of the raw value is. */
|
|
62
|
+
readonly unit: string;
|
|
63
|
+
/** What the raw number actually measures — copied into the row. */
|
|
64
|
+
readonly note: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The six factors, in the order they are reported.
|
|
68
|
+
*
|
|
69
|
+
* The weights are a judgement, and they are declared here (and surfaced in the
|
|
70
|
+
* registry entry, so they appear in `capabilities` and in the generated tool
|
|
71
|
+
* catalog) precisely so that judgement is arguable rather than hidden: errors
|
|
72
|
+
* and raw smoothness dominate, frustration signals matter, and exploration is a
|
|
73
|
+
* tiebreak. A project that disagrees passes `weights`.
|
|
74
|
+
*/
|
|
75
|
+
export declare const HEALTH_FACTORS: readonly HealthFactorSpec[];
|
|
76
|
+
/** Every factor id, for validating a `weights` override. */
|
|
77
|
+
export declare const HEALTH_FACTOR_IDS: readonly string[];
|
|
78
|
+
/** The declared default weights, as the registry entry publishes them. */
|
|
79
|
+
export declare const HEALTH_DEFAULT_WEIGHTS: Readonly<Record<string, number>>;
|
|
80
|
+
/**
|
|
81
|
+
* How many robust deviations from the project norm span half the scale.
|
|
82
|
+
*
|
|
83
|
+
* At the norm a factor scores 50; `HEALTH_Z_SPAN` deviations better scores 100
|
|
84
|
+
* and the same distance worse scores 0. Four is chosen so that the everyday
|
|
85
|
+
* range of a metric occupies the middle of the scale rather than saturating it
|
|
86
|
+
* — a scene one MAD off the norm reads 62 or 38, which is a nudge, and it takes
|
|
87
|
+
* a genuinely unusual reading to bottom out.
|
|
88
|
+
*/
|
|
89
|
+
export declare const HEALTH_Z_SPAN = 4;
|
|
90
|
+
/** Decimals a health number is rounded to before it leaves the API. */
|
|
91
|
+
export declare const HEALTH_PRECISION = 6;
|
|
92
|
+
/**
|
|
93
|
+
* Sessions below which a scene's score is not worth reading.
|
|
94
|
+
*
|
|
95
|
+
* Not a filter: the row is returned with its `sampleSize` so a caller can see
|
|
96
|
+
* why, exactly as `movers` keeps its sub-`minSample` rows.
|
|
97
|
+
*/
|
|
98
|
+
export declare const HEALTH_MIN_SESSIONS = 20;
|
|
99
|
+
/** How many scenes one request may score when the caller names none. */
|
|
100
|
+
export declare const HEALTH_DEFAULT_SCENES = 5;
|
|
101
|
+
/** The hard cap on scenes per request — the fan-out is linear in this. */
|
|
102
|
+
export declare const HEALTH_MAX_SCENES = 10;
|
|
103
|
+
/** Default window, in days. */
|
|
104
|
+
export declare const HEALTH_DEFAULT_WINDOW_DAYS = 7;
|
|
105
|
+
/**
|
|
106
|
+
* Resolve the window a health score is computed over, and the project baseline
|
|
107
|
+
* window immediately before it.
|
|
108
|
+
*
|
|
109
|
+
* **This is the one insight primitive whose window includes the bucket in
|
|
110
|
+
* progress**, and the difference is deliberate. `baseline` and `movers` floor
|
|
111
|
+
* `until` down to the last complete bucket because they report *counts*, and a
|
|
112
|
+
* third of a day of traffic compared against whole days reads as a collapse
|
|
113
|
+
* every morning. Every health factor is a **rate or a percentile** — errors per
|
|
114
|
+
* session, long frames per sampled window, the 5th-percentile FPS — and none of
|
|
115
|
+
* those is distorted by a partial bucket: half a day of data gives half the
|
|
116
|
+
* numerator *and* half the denominator.
|
|
117
|
+
*
|
|
118
|
+
* Flooring here would instead make the score answer about **yesterday**, which
|
|
119
|
+
* is the wrong answer to 'which scene is in trouble' and, on a dashboard whose
|
|
120
|
+
* range is the last hour, would show an empty tile all day.
|
|
121
|
+
*
|
|
122
|
+
* The baseline is the equal window immediately before — the same 'previous
|
|
123
|
+
* equal window' reference `movers` uses, so a health score and a movers list
|
|
124
|
+
* are read against the same past.
|
|
125
|
+
*/
|
|
126
|
+
export declare function resolveHealthWindows(opts: {
|
|
127
|
+
since?: number;
|
|
128
|
+
until?: number;
|
|
129
|
+
windowDays?: number;
|
|
130
|
+
bucket: BucketGrain;
|
|
131
|
+
now: number;
|
|
132
|
+
}): {
|
|
133
|
+
range: ResolvedWindow;
|
|
134
|
+
baseline: ResolvedWindow;
|
|
135
|
+
};
|
|
136
|
+
/** One factor's contribution to a scene's score. */
|
|
137
|
+
export interface HealthFactorRow {
|
|
138
|
+
/** The factor id — the key a `weights` override addresses. */
|
|
139
|
+
id: string;
|
|
140
|
+
/** The registry metric behind the raw value. */
|
|
141
|
+
metric: string;
|
|
142
|
+
/** The value that metric produced over the window, in `unit`. */
|
|
143
|
+
raw: number | null;
|
|
144
|
+
/** The project baseline this was normalised against — the previous window's median. */
|
|
145
|
+
baseline: number | null;
|
|
146
|
+
/** 0–100 against that baseline; 50 is exactly the project norm. `null` when unavailable. */
|
|
147
|
+
score: number | null;
|
|
148
|
+
/** The weight this factor carried. */
|
|
149
|
+
weight: number;
|
|
150
|
+
unit: string;
|
|
151
|
+
/** What the raw number is, and why it is normalised the way it is. */
|
|
152
|
+
note: string;
|
|
153
|
+
}
|
|
154
|
+
/** What `scene_health` reports. One row per scene. */
|
|
155
|
+
export interface SceneHealthRow {
|
|
156
|
+
/** The scene scored; `''` when the request spanned every scene. */
|
|
157
|
+
scene: string;
|
|
158
|
+
/** Weighted mean of the available factors' scores, 0–100; `null` when none were. */
|
|
159
|
+
score: number | null;
|
|
160
|
+
factors: HealthFactorRow[];
|
|
161
|
+
/** Sessions behind the window — what decides whether the score means anything. */
|
|
162
|
+
sampleSize: number;
|
|
163
|
+
since: number;
|
|
164
|
+
until: number;
|
|
165
|
+
}
|
|
166
|
+
/** The two bucket series one factor reads, over one window. */
|
|
167
|
+
export interface HealthSeries {
|
|
168
|
+
numerator: readonly MetricBucketRow[];
|
|
169
|
+
/** Absent for a level factor. */
|
|
170
|
+
denominator?: readonly MetricBucketRow[];
|
|
171
|
+
}
|
|
172
|
+
/** Everything `computeSceneHealth` needs about one factor. */
|
|
173
|
+
export interface HealthFactorInput {
|
|
174
|
+
/** The scene's series over the scored window. */
|
|
175
|
+
current: HealthSeries;
|
|
176
|
+
/** The project's series over the preceding equal window — the baseline. */
|
|
177
|
+
baseline: HealthSeries;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Map a raw value onto 0–100 against a baseline centre and spread.
|
|
181
|
+
*
|
|
182
|
+
* Linear in the robust z and clamped, rather than a logistic or a percentile
|
|
183
|
+
* rank: a reader has to be able to do the arithmetic backwards from the row.
|
|
184
|
+
* `null` when the baseline carried nothing to compare against — an unscored
|
|
185
|
+
* factor, never a default of 50, because "we have no history for this" and
|
|
186
|
+
* "this is exactly normal" are different statements.
|
|
187
|
+
*/
|
|
188
|
+
export declare function normaliseFactor(raw: number | null, baseline: readonly number[], direction: "up" | "down"): {
|
|
189
|
+
score: number | null;
|
|
190
|
+
centre: number | null;
|
|
191
|
+
};
|
|
192
|
+
/**
|
|
193
|
+
* Resolve the weights a request scores with.
|
|
194
|
+
*
|
|
195
|
+
* An override replaces a factor's weight; factors the override does not mention
|
|
196
|
+
* keep their declared weight, so `weights={"error_rate":0.6}` means "I care
|
|
197
|
+
* much more about errors" rather than "score errors only". Unknown ids are
|
|
198
|
+
* rejected at the route, not silently ignored.
|
|
199
|
+
*/
|
|
200
|
+
export declare function resolveWeights(override?: Readonly<Record<string, number>> | null): Record<string, number>;
|
|
201
|
+
/**
|
|
202
|
+
* Score one scene.
|
|
203
|
+
*
|
|
204
|
+
* `inputs` is keyed by factor id; a factor with no entry (a project with no XR
|
|
205
|
+
* traffic, a scene with no perf samples) is reported with `score: null` and
|
|
206
|
+
* excluded from the weighted mean rather than dropped from the row — the reason
|
|
207
|
+
* a score is missing a factor has to be visible in the answer.
|
|
208
|
+
*/
|
|
209
|
+
export declare function computeSceneHealth(opts: {
|
|
210
|
+
scene: string;
|
|
211
|
+
since: number;
|
|
212
|
+
until: number;
|
|
213
|
+
sampleSize: number;
|
|
214
|
+
inputs: Readonly<Record<string, HealthFactorInput | undefined>>;
|
|
215
|
+
weights?: Readonly<Record<string, number>> | null;
|
|
216
|
+
}): SceneHealthRow;
|
|
217
|
+
/** Least healthy first, then by scene id so the order is a function of the rows. */
|
|
218
|
+
export declare function rankSceneHealth(rows: readonly SceneHealthRow[]): SceneHealthRow[];
|
|
219
|
+
//# sourceMappingURL=health.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"health.d.ts","sourceRoot":"","sources":["../../src/insights/health.ts"],"names":[],"mappings":"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"}
|