@uptimizr/metrics 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,289 @@
1
+ /**
2
+ * Zod mirrors of the three result envelopes (ADR 0051 §2, design sketch §B.1).
3
+ *
4
+ * `format=full | table | summary` is the shared querystring of every
5
+ * registry-served aggregate endpoint, and the same three shapes are what an
6
+ * agent gets back through MCP. They are described **here**, next to the row
7
+ * schemas they wrap, because three different packages need them and none of
8
+ * them may depend on the others:
9
+ *
10
+ * - `@uptimizr/db` attaches each route's 200 response schema from the registry,
11
+ * so the collector's Zod type provider serialises a formatted response
12
+ * *through* one of these — without them a `table` or `summary` response would
13
+ * be stripped to nothing on its way out. `@uptimizr/db/summary` re-exports
14
+ * every schema below under its established names, so that package's public
15
+ * API is unchanged.
16
+ * - `@uptimizr/agent-core` derives each generated tool's `outputSchema` from
17
+ * them, and `@uptimizr/mcp` validates `structuredContent` with them. Neither
18
+ * package may depend on `@uptimizr/db` (it carries a ~37 MB DuckDB binding;
19
+ * `dependencies.test.ts` in both packages fails if it reappears) — which is
20
+ * exactly why the *pure* schemas live in this dependency-free package.
21
+ *
22
+ * Only the schemas moved. The summariser that *builds* an envelope
23
+ * (`summarizeRows`, `tableResult`, `clusterCells`, …) is still
24
+ * `@uptimizr/db/summary`'s; relocating it is #337.
25
+ */
26
+ import { z } from "zod";
27
+ import { METRIC_IDS } from "./registry.js";
28
+ /**
29
+ * `format=full | table | summary`, the shared querystring value every
30
+ * registry-served aggregate endpoint accepts. Spelled out literally rather than
31
+ * built from a `RESULT_FORMATS` array so the inferred type is the string union
32
+ * itself and a route handler keeps its narrowing.
33
+ */
34
+ export const resultFormatSchema = z.enum(["full", "table", "summary"]);
35
+ /** Any registry metric id. */
36
+ const metricIdSchema = z.enum(METRIC_IDS);
37
+ const rangeSchema = z.object({
38
+ since: z.number().nullable(),
39
+ until: z.number().nullable(),
40
+ });
41
+ /** Applied filter values are whatever the route's own schema produced. */
42
+ const filtersSchema = z.record(z.string(), z.unknown());
43
+ const sampleSizeSchema = z.object({
44
+ sessions: z.number().nullable(),
45
+ events: z.number().nullable(),
46
+ });
47
+ const limitsSchema = z.object({
48
+ maxRows: z.number().int(),
49
+ maxSummaryRows: z.number().int(),
50
+ });
51
+ const measureSchema = z
52
+ .object({
53
+ column: z.string(),
54
+ unit: z.string().nullable(),
55
+ additive: z.boolean(),
56
+ })
57
+ .nullable();
58
+ const shareIntervalSchema = z.object({ low: z.number(), high: z.number() });
59
+ const confidenceSchema = z.object({
60
+ kind: z.literal("wilson"),
61
+ level: z.number(),
62
+ note: z.string(),
63
+ });
64
+ const drillSchema = z.record(z.string(), z.string());
65
+ /**
66
+ * The runnable drill-down query a ranked row can carry (#304): the query that
67
+ * produced the digest, with one more filter. Loose on purpose — its real shape
68
+ * is `queryV1Schema` in `@uptimizr/schema`, and restating it here would create
69
+ * the second definition ADR 0051 §1 exists to prevent.
70
+ */
71
+ const drillQuerySchema = z.record(z.string(), z.unknown());
72
+ const restSchema = z.object({
73
+ rows: z.number().int(),
74
+ value: z.number().nullable(),
75
+ share: z.number().nullable(),
76
+ });
77
+ const clusterRestSchema = z.object({
78
+ clusters: z.number().int(),
79
+ cells: z.number().int(),
80
+ weight: z.number().nullable(),
81
+ share: z.number().nullable(),
82
+ });
83
+ const rankedRowSchema = z.object({
84
+ label: z.string(),
85
+ value: z.number().nullable(),
86
+ share: z.number().nullable(),
87
+ shareInterval: shareIntervalSchema.optional(),
88
+ drill: drillSchema.optional(),
89
+ drillQuery: drillQuerySchema.optional(),
90
+ });
91
+ const seriesDigestSchema = z.object({
92
+ axis: z.string(),
93
+ points: z.number().int(),
94
+ first: z.number().nullable(),
95
+ last: z.number().nullable(),
96
+ min: z.number().nullable(),
97
+ max: z.number().nullable(),
98
+ firstLabel: z.string().nullable(),
99
+ lastLabel: z.string().nullable(),
100
+ minLabel: z.string().nullable(),
101
+ maxLabel: z.string().nullable(),
102
+ trend: z.enum(["up", "down", "flat"]),
103
+ slope: z.number().nullable(),
104
+ });
105
+ const spatialClusterSchema = z.object({
106
+ centroid: z.array(z.number()),
107
+ extent: z.object({ min: z.array(z.number()), max: z.array(z.number()) }),
108
+ cells: z.number().int(),
109
+ weight: z.number(),
110
+ share: z.number().nullable(),
111
+ drill: drillSchema.optional(),
112
+ // Spatial labelling (ADR 0051 §2 / sketch §B.2, #302). Optional as a group: a
113
+ // labelled cluster carries all four; they are absent entirely when the grid is
114
+ // not world-space or the request selected no scene. `null` inside the group
115
+ // means "the scene was checked and nothing contains this hotspot".
116
+ region: z.string().nullable().optional(),
117
+ regions: z.array(z.string()).optional(),
118
+ nearestMesh: z.string().nullable().optional(),
119
+ distance: z.number().nullable().optional(),
120
+ });
121
+ const recordValueSchema = z.record(z.string(), z.union([z.string(), z.number(), z.boolean(), z.null()]));
122
+ const ratesSchema = z.record(z.string(), z.object({
123
+ value: z.number().nullable(),
124
+ numerator: z.string(),
125
+ denominator: z.string(),
126
+ }));
127
+ /** Fields every summary carries, whatever its grain. */
128
+ const summaryBase = {
129
+ metric: metricIdSchema,
130
+ range: rangeSchema,
131
+ filters: filtersSchema,
132
+ sampleSize: sampleSizeSchema,
133
+ total: z.number().nullable(),
134
+ measure: measureSchema,
135
+ confidence: confidenceSchema.optional(),
136
+ reading: z.string(),
137
+ caveats: z.array(z.string()),
138
+ };
139
+ const rankedSummarySchema = z.object({
140
+ ...summaryBase,
141
+ kind: z.literal("ranked"),
142
+ top: z.array(rankedRowSchema),
143
+ rest: restSchema,
144
+ });
145
+ const seriesSummarySchema = z.object({
146
+ ...summaryBase,
147
+ kind: z.literal("series"),
148
+ series: seriesDigestSchema,
149
+ });
150
+ const clusterSummarySchema = z.object({
151
+ ...summaryBase,
152
+ kind: z.literal("clusters"),
153
+ axes: z.array(z.string()),
154
+ occupiedCells: z.number().int(),
155
+ densityThreshold: z.number(),
156
+ clusters: z.array(spatialClusterSchema),
157
+ rest: clusterRestSchema,
158
+ });
159
+ const recordSummarySchema = z.object({
160
+ ...summaryBase,
161
+ kind: z.literal("record"),
162
+ record: recordValueSchema,
163
+ rates: ratesSchema,
164
+ });
165
+ /** `format=summary`: one of the four grain-driven shapes. */
166
+ export const summaryEnvelopeSchema = z.discriminatedUnion("kind", [
167
+ rankedSummarySchema,
168
+ seriesSummarySchema,
169
+ clusterSummarySchema,
170
+ recordSummarySchema,
171
+ ]);
172
+ /** The `meta` block `format=table` wraps a metric's rows in. */
173
+ export const tableMetaSchema = z.object({
174
+ metric: metricIdSchema,
175
+ range: rangeSchema,
176
+ filters: filtersSchema,
177
+ sampleSize: sampleSizeSchema,
178
+ rows: z.number().int(),
179
+ truncated: z.boolean(),
180
+ limits: limitsSchema,
181
+ });
182
+ /** `format=table`: the `meta` envelope around a metric's own row schema. */
183
+ export function tableEnvelopeSchema(row) {
184
+ return z.object({
185
+ meta: tableMetaSchema,
186
+ rows: z.array(row),
187
+ });
188
+ }
189
+ /**
190
+ * The result a caller gets from a surface that honours `format`: the union of
191
+ * the three envelopes.
192
+ *
193
+ * Order matters. The `full` shape is first, so a default request is parsed by
194
+ * precisely the schema it was parsed by before this existed and its bytes
195
+ * cannot drift. The envelopes are unambiguous against it — `table` is an object
196
+ * with `meta` and `rows`, `summary` an object with `kind` and `reading`, and
197
+ * neither can satisfy a row array or a stats row's required numeric columns.
198
+ *
199
+ * `full` defaults to a plain array of `row`, which is what an agent-facing
200
+ * caller wants; the collector passes its own route-level 200 schema instead,
201
+ * because a single-record route (the spatial `stats` endpoints) answers with a
202
+ * bare object rather than an array.
203
+ */
204
+ export function resultEnvelopeSchema(row, full = z.array(row)) {
205
+ return z.union([full, tableEnvelopeSchema(row), summaryEnvelopeSchema]);
206
+ }
207
+ /**
208
+ * The **object** form of {@link resultEnvelopeSchema}, for a tool that must
209
+ * advertise its result as a single JSON Schema object — which is what MCP's
210
+ * `outputSchema` is: a `type: "object"` schema the SDK validates
211
+ * `structuredContent` against, on the server with Zod and again on the client
212
+ * with Ajv.
213
+ *
214
+ * A top-level `z.union` cannot be used there. The MCP TypeScript SDK normalises
215
+ * an output schema to an object schema and **silently drops** anything that is
216
+ * not one (`normalizeObjectSchema` returns `undefined` for a union), so
217
+ * `tools/list` would advertise no output schema at all and every call would then
218
+ * fail validation — worse than the bug this replaces. So the three envelopes are
219
+ * merged into one loose object whose every key is optional:
220
+ *
221
+ * - `rows` — `format=full` (wrapped as `{ rows }` by the MCP server, so a
222
+ * single-record read looks like every other) and the rows of `format=table`.
223
+ * Its element schema stays the metric's own, so a column that is out of
224
+ * contract is still reported by name.
225
+ * - `meta` — only `format=table` carries it.
226
+ * - `kind` and the summary fields — only `format=summary` carries them, and
227
+ * `kind` says which grain-specific fields (`top`, `series`, `clusters`,
228
+ * `record`) came with it.
229
+ *
230
+ * The object is deliberately *loose*: an envelope key a newer collector adds is
231
+ * passed through rather than dropped. Callers that can express a union — a
232
+ * collector route's response schema, a test — should use
233
+ * {@link resultEnvelopeSchema}, which discriminates strictly.
234
+ */
235
+ export function structuredEnvelopeSchema(row, metric) {
236
+ // A tool answers for exactly one metric, so naming it collapses two copies
237
+ // of the 69-value registry enum (~2.7 kB per tool in `tools/list`) into a
238
+ // literal — smaller *and* more precise. Omitted, the enum stands.
239
+ const id = metric == null ? metricIdSchema : z.literal(metric);
240
+ return z.looseObject({
241
+ rows: z
242
+ .array(row)
243
+ .optional()
244
+ .describe("`format=full` and `format=table`: the result rows. Absent from a summary."),
245
+ meta: (metric == null ? tableMetaSchema : tableMetaSchema.extend({ metric: id }))
246
+ .optional()
247
+ .describe("`format=table` only: metric, range, applied filters, row count, caps."),
248
+ kind: z
249
+ .enum(["ranked", "series", "clusters", "record"])
250
+ .optional()
251
+ .describe("`format=summary` only: which digest this is."),
252
+ metric: id.optional().describe("`format=summary` only: the metric summarised."),
253
+ range: rangeSchema.optional(),
254
+ filters: filtersSchema.optional(),
255
+ sampleSize: sampleSizeSchema.optional(),
256
+ total: z.number().nullable().optional(),
257
+ measure: measureSchema.optional(),
258
+ confidence: confidenceSchema.optional(),
259
+ reading: z
260
+ .string()
261
+ .optional()
262
+ .describe("`format=summary` only: one plain-language sentence, templated — never written."),
263
+ caveats: z.array(z.string()).optional(),
264
+ top: z.array(rankedRowSchema).optional().describe('`kind: "ranked"`: the leading rows.'),
265
+ rest: z
266
+ .looseObject({
267
+ rows: z.number().int().optional(),
268
+ clusters: z.number().int().optional(),
269
+ cells: z.number().int().optional(),
270
+ value: z.number().nullable().optional(),
271
+ weight: z.number().nullable().optional(),
272
+ share: z.number().nullable().optional(),
273
+ })
274
+ .optional()
275
+ .describe("What the digest did not list individually: `rows`/`value` for a ranked digest, " +
276
+ "`clusters`/`cells`/`weight` for a spatial one."),
277
+ series: seriesDigestSchema.optional().describe('`kind: "series"`: the per-bucket digest.'),
278
+ axes: z.array(z.string()).optional(),
279
+ occupiedCells: z.number().int().optional(),
280
+ densityThreshold: z.number().optional(),
281
+ clusters: z
282
+ .array(spatialClusterSchema)
283
+ .optional()
284
+ .describe('`kind: "clusters"`: merged spatial hotspots.'),
285
+ record: recordValueSchema.optional().describe('`kind: "record"`: the single row itself.'),
286
+ rates: ratesSchema.optional(),
287
+ });
288
+ }
289
+ //# sourceMappingURL=envelopes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelopes.js","sourceRoot":"","sources":["../src/envelopes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,CAAC;AAEvE,8BAA8B;AAC9B,MAAM,cAAc,GAAG,CAAC,CAAC,IAAI,CAAC,UAA8C,CAAC,CAAC;AAE9E,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,0EAA0E;AAC1E,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAExD,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC9B,CAAC,CAAC;AAEH,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACzB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;CACjC,CAAC,CAAC;AAEH,MAAM,aAAa,GAAG,CAAC;KACpB,MAAM,CAAC;IACN,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;CACtB,CAAC;KACD,QAAQ,EAAE,CAAC;AAEd,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AAE5E,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;CACjB,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAErD;;;;;GAKG;AACH,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;AAE3D,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IAC1B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC1B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC7B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,aAAa,EAAE,mBAAmB,CAAC,QAAQ,EAAE;IAC7C,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;IAC7B,UAAU,EAAE,gBAAgB,CAAC,QAAQ,EAAE;CACxC,CAAC,CAAC;AAEH,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACxB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,GAAG,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC1B,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACjC,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC/B,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC7B,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IAC7B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;IACxE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACvB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;IAC7B,8EAA8E;IAC9E,+EAA+E;IAC/E,4EAA4E;IAC5E,mEAAmE;IACnE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IACxC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;IACvC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC7C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;CAC3C,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAChC,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CACzD,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAC1B,CAAC,CAAC,MAAM,EAAE,EACV,CAAC,CAAC,MAAM,CAAC;IACP,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;CACxB,CAAC,CACH,CAAC;AAEF,wDAAwD;AACxD,MAAM,WAAW,GAAG;IAClB,MAAM,EAAE,cAAc;IACtB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,aAAa;IACtB,UAAU,EAAE,gBAAgB;IAC5B,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC5B,OAAO,EAAE,aAAa;IACtB,UAAU,EAAE,gBAAgB,CAAC,QAAQ,EAAE;IACvC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;CAC7B,CAAC;AAEF,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,GAAG,WAAW;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC;IAC7B,IAAI,EAAE,UAAU;CACjB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,GAAG,WAAW;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,MAAM,EAAE,kBAAkB;CAC3B,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,GAAG,WAAW;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACzB,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IAC/B,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC;IACvC,IAAI,EAAE,iBAAiB;CACxB,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,CAAC,CAAC,MAAM,CAAC;IACnC,GAAG,WAAW;IACd,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;IACzB,MAAM,EAAE,iBAAiB;IACzB,KAAK,EAAE,WAAW;CACnB,CAAC,CAAC;AAEH,6DAA6D;AAC7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,kBAAkB,CAAC,MAAM,EAAE;IAChE,mBAAmB;IACnB,mBAAmB;IACnB,oBAAoB;IACpB,mBAAmB;CACpB,CAAC,CAAC;AAEH,gEAAgE;AAChE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,MAAM,EAAE,cAAc;IACtB,KAAK,EAAE,WAAW;IAClB,OAAO,EAAE,aAAa;IACtB,UAAU,EAAE,gBAAgB;IAC5B,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE;IACtB,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE;IACtB,MAAM,EAAE,YAAY;CACrB,CAAC,CAAC;AAEH,4EAA4E;AAC5E,MAAM,UAAU,mBAAmB,CAAC,GAAc;IAChD,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,IAAI,EAAE,eAAe;QACrB,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;KACnB,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,oBAAoB,CAAC,GAAc,EAAE,OAAkB,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC;IACjF,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,mBAAmB,CAAC,GAAG,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC;AAC1E,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,UAAU,wBAAwB,CAAC,GAAc,EAAE,MAAe;IACtE,2EAA2E;IAC3E,0EAA0E;IAC1E,kEAAkE;IAClE,MAAM,EAAE,GAAG,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAC/D,OAAO,CAAC,CAAC,WAAW,CAAC;QACnB,IAAI,EAAE,CAAC;aACJ,KAAK,CAAC,GAAG,CAAC;aACV,QAAQ,EAAE;aACV,QAAQ,CAAC,2EAA2E,CAAC;QACxF,IAAI,EAAE,CAAC,MAAM,IAAI,IAAI,CAAC,CAAC,CAAC,eAAe,CAAC,CAAC,CAAC,eAAe,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC;aAC9E,QAAQ,EAAE;aACV,QAAQ,CAAC,uEAAuE,CAAC;QACpF,IAAI,EAAE,CAAC;aACJ,IAAI,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;aAChD,QAAQ,EAAE;aACV,QAAQ,CAAC,8CAA8C,CAAC;QAC3D,MAAM,EAAE,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,+CAA+C,CAAC;QAC/E,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;QAC7B,OAAO,EAAE,aAAa,CAAC,QAAQ,EAAE;QACjC,UAAU,EAAE,gBAAgB,CAAC,QAAQ,EAAE;QACvC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;QACvC,OAAO,EAAE,aAAa,CAAC,QAAQ,EAAE;QACjC,UAAU,EAAE,gBAAgB,CAAC,QAAQ,EAAE;QACvC,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,gFAAgF,CAAC;QAC7F,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACvC,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,qCAAqC,CAAC;QACxF,IAAI,EAAE,CAAC;aACJ,WAAW,CAAC;YACX,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;YACjC,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;YACrC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;YAClC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;YACvC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;YACxC,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;SACxC,CAAC;aACD,QAAQ,EAAE;aACV,QAAQ,CACP,iFAAiF;YAC/E,gDAAgD,CACnD;QACH,MAAM,EAAE,kBAAkB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QAC1F,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;QACpC,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;QAC1C,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;QACvC,QAAQ,EAAE,CAAC;aACR,KAAK,CAAC,oBAAoB,CAAC;aAC3B,QAAQ,EAAE;aACV,QAAQ,CAAC,8CAA8C,CAAC;QAC3D,MAAM,EAAE,iBAAiB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QACzF,KAAK,EAAE,WAAW,CAAC,QAAQ,EAAE;KAC9B,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -24,6 +24,13 @@
24
24
  * metric?.row; // z.ZodObject — the shape of one row
25
25
  * ```
26
26
  */
27
- export { AGGREGATION_BUILDER_NAMES, DIMENSION_COLUMNS, FILTER_TARGETS, METRIC_BY_BUILDER, METRIC_IDS, METRIC_REGISTRY, allMetrics, getMetric, isMetricId, isResourceMetric, metricForBuilder, } from "./registry.js";
28
- export type { AggregationBuilderName, ColumnSemantics, ColumnUnit, DimensionId, FilterId, FilterOptionInterface, FilterTarget, MetricCategory, MetricComparison, MetricDefinition, MetricEndpoint, MetricGrain, MetricId, MetricRegistry, NoUnregisteredAggregations, UnregisteredAggregation, } from "./registry.js";
27
+ export { AGGREGATION_BUILDER_NAMES, DIMENSION_COLUMNS, DIMENSION_ROW_COLUMNS, FILTER_TARGETS, GENERIC_DIMENSIONS, METRIC_BY_BUILDER, METRIC_IDS, METRIC_REGISTRY, allMetrics, getMetric, isMetricId, isAggregateMetric, isDerivedMetric, isResourceMetric, metricCapability, metricForBuilder, } from "./registry.js";
28
+ export { REQUIRED_FILTERS, dimensionColumn, genericDimensions, nativeDimensions, orderableColumns, queryTier, queryableFilters, requiredFilters, segmentableDimensions, validateQuery, } from "./query.js";
29
+ export type { QueryIssue, QueryIssueCode, QueryTier, QueryValidation } from "./query.js";
30
+ export { PANEL_CHART_RULES, axisColumn, chartSuitsMetric, chartsForMetric, defaultEncoding, labelColumn, measureColumn, resultColumns, suggestChart, validatePanelSpec, } from "./panelSpec.js";
31
+ export type { PanelChartRule, PanelSpecIssue, PanelSpecIssueCode, PanelSpecValidation, } from "./panelSpec.js";
32
+ export type { AggregationBuilderName, ColumnSemantics, ColumnUnit, DimensionId, FilterId, FilterOptionInterface, FilterTarget, GenericGroupBy, GenericMeasure, GenericMeasureKind, GenericScope, MetricCapability, MetricCategory, MetricComparison, MetricDefinition, MetricDerivation, MetricEndpoint, MetricGrain, MetricId, MetricRegistry, NoUnregisteredAggregations, UnregisteredAggregation, } from "./registry.js";
33
+ export { resultEnvelopeSchema, resultFormatSchema, structuredEnvelopeSchema, summaryEnvelopeSchema, tableEnvelopeSchema, tableMetaSchema, } from "./envelopes.js";
34
+ export { NARRATIVE_ENTRY_KINDS, NARRATIVE_LIMITS, narrativeEntryKindSchema, narrativeRefsSchema, sessionNarrativeEntrySchema, sessionNarrativeTotalsSchema, } from "./narrative.js";
35
+ export type { NarrativeEntryKind, NarrativeRefs, SessionNarrativeEntry, SessionNarrativeTotals, } from "./narrative.js";
29
36
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,YAAY,EACV,sBAAsB,EACtB,eAAe,EACf,UAAU,EACV,WAAW,EACX,QAAQ,EACR,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,QAAQ,EACR,cAAc,EACd,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAKvB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAMzF,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AACxB,YAAY,EACV,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,sBAAsB,EACtB,eAAe,EACf,UAAU,EACV,WAAW,EACX,QAAQ,EACR,qBAAqB,EACrB,YAAY,EACZ,cAAc,EACd,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,cAAc,EACd,WAAW,EACX,QAAQ,EACR,cAAc,EACd,0BAA0B,EAC1B,uBAAuB,GACxB,MAAM,eAAe,CAAC;AAQvB,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAOxB,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC;AAExB,YAAY,EACV,kBAAkB,EAClB,aAAa,EACb,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -24,5 +24,27 @@
24
24
  * metric?.row; // z.ZodObject — the shape of one row
25
25
  * ```
26
26
  */
27
- export { AGGREGATION_BUILDER_NAMES, DIMENSION_COLUMNS, FILTER_TARGETS, METRIC_BY_BUILDER, METRIC_IDS, METRIC_REGISTRY, allMetrics, getMetric, isMetricId, isResourceMetric, metricForBuilder, } from "./registry.js";
27
+ export { AGGREGATION_BUILDER_NAMES, DIMENSION_COLUMNS, DIMENSION_ROW_COLUMNS, FILTER_TARGETS, GENERIC_DIMENSIONS, METRIC_BY_BUILDER, METRIC_IDS, METRIC_REGISTRY, allMetrics, getMetric, isMetricId, isAggregateMetric, isDerivedMetric, isResourceMetric, metricCapability, metricForBuilder, } from "./registry.js";
28
+ // --- Query DSL validation (ADR 0051 §3) ---
29
+ // The registry half of validating a `queryV1` document: `@uptimizr/schema`
30
+ // checks the shape, this checks the vocabulary.
31
+ export { REQUIRED_FILTERS, dimensionColumn, genericDimensions, nativeDimensions, orderableColumns, queryTier, queryableFilters, requiredFilters, segmentableDimensions, validateQuery, } from "./query.js";
32
+ // --- Declarative panel specs (ADR 0051 §7 / sketch §G.3) -------------------
33
+ // The registry half of validating a `panelSpecV1`: its query through
34
+ // `validateQuery`, then the two questions only the registry can answer — does
35
+ // this chart suit the metric's grain, and do these encoding columns exist.
36
+ export { PANEL_CHART_RULES, axisColumn, chartSuitsMetric, chartsForMetric, defaultEncoding, labelColumn, measureColumn, resultColumns, suggestChart, validatePanelSpec, } from "./panelSpec.js";
37
+ // --- Result envelopes (ADR 0051 §2) ---
38
+ // The Zod mirrors of `format=full | table | summary`. They live here, next to
39
+ // the row schemas they wrap, so the collector (`@uptimizr/db`), the generated
40
+ // tool catalog (`@uptimizr/agent-core`) and the MCP server can all describe the
41
+ // same three shapes without any of them depending on the others. The summariser
42
+ // that *builds* an envelope stays in `@uptimizr/db/summary` (#337).
43
+ export { resultEnvelopeSchema, resultFormatSchema, structuredEnvelopeSchema, summaryEnvelopeSchema, tableEnvelopeSchema, tableMetaSchema, } from "./envelopes.js";
44
+ // --- Session narrative (ADR 0051 §7, design sketch §G.2) -------------------
45
+ //
46
+ // The shapes and bounds of the `query:raw`-gated session narrative, shared by
47
+ // the compaction in `@uptimizr/db`, the collector route that serves it and the
48
+ // `session_narrative` registry entry above.
49
+ export { NARRATIVE_ENTRY_KINDS, NARRATIVE_LIMITS, narrativeEntryKindSchema, narrativeRefsSchema, sessionNarrativeEntrySchema, sessionNarrativeTotalsSchema, } from "./narrative.js";
28
50
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,EACV,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,OAAO,EACL,yBAAyB,EACzB,iBAAiB,EACjB,qBAAqB,EACrB,cAAc,EACd,kBAAkB,EAClB,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,UAAU,EACV,SAAS,EACT,UAAU,EACV,iBAAiB,EACjB,eAAe,EACf,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,GACjB,MAAM,eAAe,CAAC;AAEvB,6CAA6C;AAC7C,2EAA2E;AAC3E,gDAAgD;AAChD,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,iBAAiB,EACjB,gBAAgB,EAChB,gBAAgB,EAChB,SAAS,EACT,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,aAAa,GACd,MAAM,YAAY,CAAC;AAGpB,8EAA8E;AAC9E,qEAAqE;AACrE,8EAA8E;AAC9E,2EAA2E;AAC3E,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,WAAW,EACX,aAAa,EACb,aAAa,EACb,YAAY,EACZ,iBAAiB,GAClB,MAAM,gBAAgB,CAAC;AAiCxB,yCAAyC;AACzC,8EAA8E;AAC9E,8EAA8E;AAC9E,gFAAgF;AAChF,gFAAgF;AAChF,oEAAoE;AACpE,OAAO,EACL,oBAAoB,EACpB,kBAAkB,EAClB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,eAAe,GAChB,MAAM,gBAAgB,CAAC;AAExB,8EAA8E;AAC9E,EAAE;AACF,8EAA8E;AAC9E,+EAA+E;AAC/E,4CAA4C;AAC5C,OAAO,EACL,qBAAqB,EACrB,gBAAgB,EAChB,wBAAwB,EACxB,mBAAmB,EACnB,2BAA2B,EAC3B,4BAA4B,GAC7B,MAAM,gBAAgB,CAAC"}
@@ -0,0 +1,164 @@
1
+ /**
2
+ * The **session narrative** contract (ADR 0051 §7, design sketch §G.2).
3
+ *
4
+ * A narrative is an ordered, compacted account of what one session did — scene
5
+ * changes, mesh dwell, interactions, performance dips, errors and the reason it
6
+ * ended — with every timestamp relative to the session's first event. It exists
7
+ * because the two things an agent could otherwise ask for are both useless to
8
+ * it: the aggregate metrics say nothing about *one* session, and the raw NDJSON
9
+ * stream is tens of thousands of lines of sampled telemetry.
10
+ *
11
+ * Only the **shapes and bounds** live here, in the dependency-free registry
12
+ * package, because three packages need them and none of them may depend on the
13
+ * others:
14
+ *
15
+ * - `@uptimizr/db` computes a narrative from `AnyEvent[]` (`src/narrative/`);
16
+ * - the collector serves it on `GET /api/v1/sessions/:id/narrative` and bounds
17
+ * its querystring with the same numbers;
18
+ * - the registry entry below it (`session_narrative`) advertises the row schema
19
+ * to OpenAPI, the agent tool catalog and the docs tables.
20
+ *
21
+ * **Privacy (ADR 0003).** A narrative is derived from raw per-session events, so
22
+ * it is reachable only on a collector with `ENABLE_RAW_SESSION_RETENTION` and
23
+ * only with a key holding `query:raw`. Even then it is a *projection*: an entry
24
+ * carries a relative timestamp, a templated one-line summary and at most a mesh
25
+ * name, a scene id and a custom-event name. It never carries the visitor hash,
26
+ * the page URL, `pageMeta`, positions, rays, or anything from the `device` block
27
+ * beyond the engine/graphics API. Custom-event **property values** are excluded
28
+ * unless the caller explicitly asks for them; the property *keys* are always
29
+ * safe to show because they are developer-chosen field names.
30
+ */
31
+ import { z } from "zod";
32
+ /**
33
+ * What one narrative entry is about.
34
+ *
35
+ * - `scene` — the session entered a scene (`session_start` or `scene_change`).
36
+ * - `dwell` — a mesh held the viewer's attention for at least `minDwellMs`,
37
+ * aggregated across the session from `mesh_visibility` / `hover_dwell`.
38
+ * - `interaction` — a discrete act: a mesh interaction, a click that hit a mesh,
39
+ * a named input action, or a custom event.
40
+ * - `perf_dip` — a run of consecutive `frame_perf` samples below `fpsThreshold`,
41
+ * collapsed into one entry with the run's duration and sample count.
42
+ * - `error` — a `runtime_error`, message truncated.
43
+ * - `diagnostic` — a `graphics_diagnostic`, by category and severity.
44
+ * - `capability` — a `capability_change` (quality drop, tracking loss, backend
45
+ * fallback).
46
+ * - `xr` — entering/leaving immersive input, and a boundary-proximity summary.
47
+ * - `end` — how the session finished (`session_end` reason), when it reported.
48
+ * - `summary` — the single closing entry carrying the session's totals.
49
+ */
50
+ export declare const NARRATIVE_ENTRY_KINDS: readonly ["scene", "dwell", "interaction", "perf_dip", "error", "diagnostic", "capability", "xr", "end", "summary"];
51
+ /** One narrative entry kind. */
52
+ export type NarrativeEntryKind = (typeof NARRATIVE_ENTRY_KINDS)[number];
53
+ /** {@link NARRATIVE_ENTRY_KINDS} as a Zod enum. */
54
+ export declare const narrativeEntryKindSchema: z.ZodEnum<{
55
+ scene: "scene";
56
+ dwell: "dwell";
57
+ interaction: "interaction";
58
+ perf_dip: "perf_dip";
59
+ error: "error";
60
+ diagnostic: "diagnostic";
61
+ capability: "capability";
62
+ xr: "xr";
63
+ end: "end";
64
+ summary: "summary";
65
+ }>;
66
+ /**
67
+ * The named things an entry points at. Deliberately only three, and all three
68
+ * are developer-assigned identifiers rather than anything about a person: the
69
+ * mesh/object name, the scene id, and the name of a custom event or input
70
+ * action.
71
+ */
72
+ export declare const narrativeRefsSchema: z.ZodObject<{
73
+ mesh: z.ZodOptional<z.ZodString>;
74
+ scene: z.ZodOptional<z.ZodString>;
75
+ name: z.ZodOptional<z.ZodString>;
76
+ }, z.core.$strip>;
77
+ /** What an entry points at — see {@link narrativeRefsSchema}. */
78
+ export type NarrativeRefs = z.infer<typeof narrativeRefsSchema>;
79
+ /**
80
+ * Session-wide totals, carried on the closing `summary` entry so a reader that
81
+ * only keeps the last line still knows the shape of what it just read.
82
+ */
83
+ export declare const sessionNarrativeTotalsSchema: z.ZodObject<{
84
+ events: z.ZodNumber;
85
+ durationMs: z.ZodNumber;
86
+ scenes: z.ZodNumber;
87
+ meshes: z.ZodNumber;
88
+ interactions: z.ZodNumber;
89
+ dips: z.ZodNumber;
90
+ errors: z.ZodNumber;
91
+ }, z.core.$strip>;
92
+ /** Session-wide totals — see {@link sessionNarrativeTotalsSchema}. */
93
+ export type SessionNarrativeTotals = z.infer<typeof sessionNarrativeTotalsSchema>;
94
+ /**
95
+ * One line of the narrative.
96
+ *
97
+ * `summary` is a **templated** one-line sentence composed from the fields
98
+ * already on the entry — never free text copied out of an event payload — so
99
+ * that what an LLM reads cannot contain anything the structured fields do not.
100
+ */
101
+ export declare const sessionNarrativeEntrySchema: z.ZodObject<{
102
+ tMs: z.ZodNumber;
103
+ kind: z.ZodEnum<{
104
+ scene: "scene";
105
+ dwell: "dwell";
106
+ interaction: "interaction";
107
+ perf_dip: "perf_dip";
108
+ error: "error";
109
+ diagnostic: "diagnostic";
110
+ capability: "capability";
111
+ xr: "xr";
112
+ end: "end";
113
+ summary: "summary";
114
+ }>;
115
+ summary: z.ZodString;
116
+ refs: z.ZodObject<{
117
+ mesh: z.ZodOptional<z.ZodString>;
118
+ scene: z.ZodOptional<z.ZodString>;
119
+ name: z.ZodOptional<z.ZodString>;
120
+ }, z.core.$strip>;
121
+ durationMs: z.ZodOptional<z.ZodNumber>;
122
+ count: z.ZodOptional<z.ZodNumber>;
123
+ totals: z.ZodOptional<z.ZodObject<{
124
+ events: z.ZodNumber;
125
+ durationMs: z.ZodNumber;
126
+ scenes: z.ZodNumber;
127
+ meshes: z.ZodNumber;
128
+ interactions: z.ZodNumber;
129
+ dips: z.ZodNumber;
130
+ errors: z.ZodNumber;
131
+ }, z.core.$strip>>;
132
+ truncated: z.ZodOptional<z.ZodBoolean>;
133
+ }, z.core.$strip>;
134
+ /** One line of the narrative — see {@link sessionNarrativeEntrySchema}. */
135
+ export type SessionNarrativeEntry = z.infer<typeof sessionNarrativeEntrySchema>;
136
+ /**
137
+ * The bounds and defaults every consumer shares. The collector's querystring
138
+ * schema, the generated tool's input schema and the compaction function all read
139
+ * them from here, so "the default dwell floor" is one number rather than three.
140
+ */
141
+ export declare const NARRATIVE_LIMITS: {
142
+ /** Default dwell floor: below this a mesh is a glance, not attention. */
143
+ readonly defaultMinDwellMs: 1000;
144
+ /** Largest dwell floor a caller may ask for (one hour). */
145
+ readonly maxMinDwellMs: 3600000;
146
+ /** Default FPS floor below which a frame sample counts towards a dip. */
147
+ readonly defaultFpsThreshold: 30;
148
+ /** Largest FPS floor a caller may ask for. */
149
+ readonly maxFpsThreshold: 240;
150
+ /**
151
+ * Consecutive sub-threshold `frame_perf` samples before a dip is reported.
152
+ * Two, so a single unlucky sample (a tab switch, a GC pause) is not a story.
153
+ */
154
+ readonly dipMinSamples: 2;
155
+ /** Default entry cap — the "under 200 lines" bound issue #314 asks for. */
156
+ readonly defaultMaxEntries: 200;
157
+ /** Hard cap: no caller can ask for an unbounded narrative (ADR 0051 §9). */
158
+ readonly maxMaxEntries: 1000;
159
+ /** Error/diagnostic messages are truncated to this many characters. */
160
+ readonly maxMessageLength: 200;
161
+ /** At most this many custom-event property **keys** are listed per entry. */
162
+ readonly maxCustomPropKeys: 12;
163
+ };
164
+ //# sourceMappingURL=narrative.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"narrative.d.ts","sourceRoot":"","sources":["../src/narrative.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,qBAAqB,qHAWxB,CAAC;AAEX,gCAAgC;AAChC,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,qBAAqB,CAAC,CAAC,MAAM,CAAC,CAAC;AAExE,mDAAmD;AACnD,eAAO,MAAM,wBAAwB;;;;;;;;;;;EAAgC,CAAC;AAEtE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB;;;;iBAI9B,CAAC;AAEH,iEAAiE;AACjE,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,mBAAmB,CAAC,CAAC;AAEhE;;;GAGG;AACH,eAAO,MAAM,4BAA4B;;;;;;;;iBAevC,CAAC;AAEH,sEAAsE;AACtE,MAAM,MAAM,sBAAsB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,4BAA4B,CAAC,CAAC;AAElF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAmBtC,CAAC;AAEH,2EAA2E;AAC3E,MAAM,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,2BAA2B,CAAC,CAAC;AAEhF;;;;GAIG;AACH,eAAO,MAAM,gBAAgB;IAC3B,yEAAyE;;IAEzE,2DAA2D;;IAE3D,yEAAyE;;IAEzE,8CAA8C;;IAE9C;;;OAGG;;IAEH,2EAA2E;;IAE3E,4EAA4E;;IAE5E,uEAAuE;;IAEvE,6EAA6E;;CAErE,CAAC"}