@bli-cockpit/telemetry-core 0.1.32 → 0.1.33

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.
@@ -106,6 +106,47 @@ export declare const CollectorHeartbeatSchema: z.ZodObject<{
106
106
  hook_printed_24h: z.ZodOptional<z.ZodNumber>;
107
107
  hook_failed_24h: z.ZodOptional<z.ZodNumber>;
108
108
  hook_stats_reason: z.ZodOptional<z.ZodString>;
109
+ hook_performance: z.ZodOptional<z.ZodObject<{
110
+ schema_version: z.ZodLiteral<"memory-hook-performance.v1">;
111
+ window_start: z.ZodString;
112
+ window_end: z.ZodString;
113
+ sampling_since: z.ZodNullable<z.ZodString>;
114
+ samples: z.ZodNumber;
115
+ outcomes: z.ZodObject<{
116
+ printed: z.ZodNumber;
117
+ empty: z.ZodNumber;
118
+ timeouts: z.ZodNumber;
119
+ failed: z.ZodNumber;
120
+ skipped: z.ZodNumber;
121
+ }, z.core.$strict>;
122
+ duration_by_cache: z.ZodObject<{
123
+ hit: z.ZodArray<z.ZodNumber>;
124
+ miss: z.ZodArray<z.ZodNumber>;
125
+ shared: z.ZodArray<z.ZodNumber>;
126
+ unknown: z.ZodArray<z.ZodNumber>;
127
+ }, z.core.$strict>;
128
+ producer_versions: z.ZodArray<z.ZodObject<{
129
+ version: z.ZodString;
130
+ samples: z.ZodNumber;
131
+ }, z.core.$strict>>;
132
+ invalid_samples: z.ZodNumber;
133
+ incomplete_samples: z.ZodNumber;
134
+ unreadable_samples: z.ZodNumber;
135
+ capped: z.ZodBoolean;
136
+ reasons: z.ZodArray<z.ZodEnum<{
137
+ no_samples: "no_samples";
138
+ partial_window: "partial_window";
139
+ lease_absent: "lease_absent";
140
+ lease_expired: "lease_expired";
141
+ lease_invalid: "lease_invalid";
142
+ read_failed: "read_failed";
143
+ read_limit: "read_limit";
144
+ invalid_samples: "invalid_samples";
145
+ incomplete_samples: "incomplete_samples";
146
+ unreadable_samples: "unreadable_samples";
147
+ cleanup_failed: "cleanup_failed";
148
+ }>>;
149
+ }, z.core.$strict>>;
109
150
  }, z.core.$strict>>;
110
151
  setup_receipt: z.ZodOptional<z.ZodObject<{
111
152
  schema_version: z.ZodLiteral<"setup-receipt.v1">;
@@ -2,9 +2,9 @@ import { z } from "zod";
2
2
  export declare const EvidenceCompletenessStatusSchema: z.ZodEnum<{
3
3
  unknown: "unknown";
4
4
  failed: "failed";
5
+ empty: "empty";
5
6
  complete: "complete";
6
7
  partial: "partial";
7
- empty: "empty";
8
8
  unavailable: "unavailable";
9
9
  }>;
10
10
  export type EvidenceCompletenessStatus = z.infer<typeof EvidenceCompletenessStatusSchema>;
@@ -71,9 +71,9 @@ export declare const EvidenceCompletenessPayloadSchema: z.ZodObject<{
71
71
  status: z.ZodEnum<{
72
72
  unknown: "unknown";
73
73
  failed: "failed";
74
+ empty: "empty";
74
75
  complete: "complete";
75
76
  partial: "partial";
76
- empty: "empty";
77
77
  unavailable: "unavailable";
78
78
  }>;
79
79
  generated_at: z.ZodString;
package/dist/index.d.ts CHANGED
@@ -10,6 +10,7 @@ export * from "./evidence-upload.js";
10
10
  export * from "./ingest-dto.js";
11
11
  export * from "./local-config.js";
12
12
  export * from "./memory-hook-stats.js";
13
+ export * from "./memory-hook-performance.js";
13
14
  export * from "./memory-install-receipt.js";
14
15
  export * from "./paths.js";
15
16
  export * from "./privacy.js";
package/dist/index.js CHANGED
@@ -10,6 +10,7 @@ export * from "./evidence-upload.js";
10
10
  export * from "./ingest-dto.js";
11
11
  export * from "./local-config.js";
12
12
  export * from "./memory-hook-stats.js";
13
+ export * from "./memory-hook-performance.js";
13
14
  export * from "./memory-install-receipt.js";
14
15
  export * from "./paths.js";
15
16
  export * from "./privacy.js";
@@ -105,9 +105,9 @@ export declare const TelemetryIngestEventDtoSchema: z.ZodObject<{
105
105
  status: z.ZodEnum<{
106
106
  unknown: "unknown";
107
107
  failed: "failed";
108
+ empty: "empty";
108
109
  complete: "complete";
109
110
  partial: "partial";
110
- empty: "empty";
111
111
  unavailable: "unavailable";
112
112
  }>;
113
113
  generated_at: z.ZodString;
@@ -584,9 +584,9 @@ export declare const TelemetryIngestEnvelopeSchema: z.ZodObject<{
584
584
  status: z.ZodEnum<{
585
585
  unknown: "unknown";
586
586
  failed: "failed";
587
+ empty: "empty";
587
588
  complete: "complete";
588
589
  partial: "partial";
589
- empty: "empty";
590
590
  unavailable: "unavailable";
591
591
  }>;
592
592
  generated_at: z.ZodString;
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Content-free prompt-hook performance samples (BLI-3876).
3
+ *
4
+ * This module is the shared wire and local-file contract only. It deliberately
5
+ * has no filesystem effects: the hook writer and collector reader own I/O.
6
+ * Samples carry closed labels, durations and timestamps, never prompt text,
7
+ * hashes or memory content.
8
+ */
9
+ import { z } from "zod";
10
+ export declare const MEMORY_HOOK_SAMPLE_SCHEMA_VERSION = "memory-hook-sample.v1";
11
+ export declare const MEMORY_HOOK_SAMPLING_LEASE_SCHEMA_VERSION = "memory-hook-sampling-lease.v1";
12
+ export declare const MEMORY_HOOK_PERFORMANCE_SCHEMA_VERSION = "memory-hook-performance.v1";
13
+ export declare const MEMORY_HOOK_CACHE_OUTCOMES: readonly ["hit", "miss", "shared", "unknown"];
14
+ export type MemoryHookCacheOutcome = (typeof MEMORY_HOOK_CACHE_OUTCOMES)[number];
15
+ export declare const MEMORY_HOOK_SAMPLE_OUTCOMES: readonly ["printed", "empty", "timeouts", "failed", "skipped"];
16
+ export type MemoryHookSampleOutcome = (typeof MEMORY_HOOK_SAMPLE_OUTCOMES)[number];
17
+ export declare const MemoryHookSampleSchema: z.ZodObject<{
18
+ schema_version: z.ZodLiteral<"memory-hook-sample.v1">;
19
+ recorded_at: z.ZodString;
20
+ elapsed_ms: z.ZodNumber;
21
+ outcome: z.ZodEnum<{
22
+ failed: "failed";
23
+ skipped: "skipped";
24
+ printed: "printed";
25
+ empty: "empty";
26
+ timeouts: "timeouts";
27
+ }>;
28
+ embed_cache: z.ZodEnum<{
29
+ unknown: "unknown";
30
+ hit: "hit";
31
+ miss: "miss";
32
+ shared: "shared";
33
+ }>;
34
+ producer_version: z.ZodString;
35
+ }, z.core.$strict>;
36
+ export type MemoryHookSample = z.infer<typeof MemoryHookSampleSchema>;
37
+ export declare const MemoryHookSamplingLeaseSchema: z.ZodObject<{
38
+ schema_version: z.ZodLiteral<"memory-hook-sampling-lease.v1">;
39
+ continuous_since: z.ZodString;
40
+ expires_at: z.ZodString;
41
+ }, z.core.$strict>;
42
+ export type MemoryHookSamplingLease = z.infer<typeof MemoryHookSamplingLeaseSchema>;
43
+ /** The samples directory below the user's existing Cockpit state directory. */
44
+ export declare const MEMORY_HOOK_SAMPLES_DIRECTORY_NAME = "memory-hook-samples";
45
+ export declare function memoryHookSamplesDirectory(homeDir: string): string;
46
+ export declare const MEMORY_HOOK_HISTOGRAM_BIN_WIDTH_MS = 100;
47
+ export declare const MEMORY_HOOK_HISTOGRAM_LENGTH = 51;
48
+ /** A fresh [0,100), ... [4900,5000), [5000,infinity) histogram. */
49
+ export declare function blankHistogram(): number[];
50
+ /** Add one valid duration and return the same histogram for convenient chaining. */
51
+ export declare function addDuration(histogram: number[], durationMs: number): number[];
52
+ /**
53
+ * Return the nearest-rank bin bounds. The result never interpolates between
54
+ * bins, and the open-ended final bin has no finite upper bound.
55
+ */
56
+ export declare function histogramPercentileBounds(histogram: number[], percentile: number): {
57
+ lower_ms: number;
58
+ upper_ms: number | null;
59
+ } | null;
60
+ export declare const MEMORY_HOOK_PERFORMANCE_REASONS: readonly ["no_samples", "partial_window", "lease_absent", "lease_expired", "lease_invalid", "read_failed", "read_limit", "invalid_samples", "incomplete_samples", "unreadable_samples", "cleanup_failed"];
61
+ export declare const MemoryHookPerformanceSchema: z.ZodObject<{
62
+ schema_version: z.ZodLiteral<"memory-hook-performance.v1">;
63
+ window_start: z.ZodString;
64
+ window_end: z.ZodString;
65
+ sampling_since: z.ZodNullable<z.ZodString>;
66
+ samples: z.ZodNumber;
67
+ outcomes: z.ZodObject<{
68
+ printed: z.ZodNumber;
69
+ empty: z.ZodNumber;
70
+ timeouts: z.ZodNumber;
71
+ failed: z.ZodNumber;
72
+ skipped: z.ZodNumber;
73
+ }, z.core.$strict>;
74
+ duration_by_cache: z.ZodObject<{
75
+ hit: z.ZodArray<z.ZodNumber>;
76
+ miss: z.ZodArray<z.ZodNumber>;
77
+ shared: z.ZodArray<z.ZodNumber>;
78
+ unknown: z.ZodArray<z.ZodNumber>;
79
+ }, z.core.$strict>;
80
+ producer_versions: z.ZodArray<z.ZodObject<{
81
+ version: z.ZodString;
82
+ samples: z.ZodNumber;
83
+ }, z.core.$strict>>;
84
+ invalid_samples: z.ZodNumber;
85
+ incomplete_samples: z.ZodNumber;
86
+ unreadable_samples: z.ZodNumber;
87
+ capped: z.ZodBoolean;
88
+ reasons: z.ZodArray<z.ZodEnum<{
89
+ no_samples: "no_samples";
90
+ partial_window: "partial_window";
91
+ lease_absent: "lease_absent";
92
+ lease_expired: "lease_expired";
93
+ lease_invalid: "lease_invalid";
94
+ read_failed: "read_failed";
95
+ read_limit: "read_limit";
96
+ invalid_samples: "invalid_samples";
97
+ incomplete_samples: "incomplete_samples";
98
+ unreadable_samples: "unreadable_samples";
99
+ cleanup_failed: "cleanup_failed";
100
+ }>>;
101
+ }, z.core.$strict>;
102
+ export type MemoryHookPerformance = z.infer<typeof MemoryHookPerformanceSchema>;
@@ -0,0 +1,208 @@
1
+ /**
2
+ * Content-free prompt-hook performance samples (BLI-3876).
3
+ *
4
+ * This module is the shared wire and local-file contract only. It deliberately
5
+ * has no filesystem effects: the hook writer and collector reader own I/O.
6
+ * Samples carry closed labels, durations and timestamps, never prompt text,
7
+ * hashes or memory content.
8
+ */
9
+ import { z } from "zod";
10
+ import { IsoDateTimeSchema } from "./common.js";
11
+ import { getUserLocalCockpitPaths } from "./paths.js";
12
+ export const MEMORY_HOOK_SAMPLE_SCHEMA_VERSION = "memory-hook-sample.v1";
13
+ export const MEMORY_HOOK_SAMPLING_LEASE_SCHEMA_VERSION = "memory-hook-sampling-lease.v1";
14
+ export const MEMORY_HOOK_PERFORMANCE_SCHEMA_VERSION = "memory-hook-performance.v1";
15
+ export const MEMORY_HOOK_CACHE_OUTCOMES = [
16
+ "hit",
17
+ "miss",
18
+ "shared",
19
+ "unknown",
20
+ ];
21
+ export const MEMORY_HOOK_SAMPLE_OUTCOMES = [
22
+ "printed",
23
+ "empty",
24
+ "timeouts",
25
+ "failed",
26
+ "skipped",
27
+ ];
28
+ const CacheOutcomeSchema = z.enum(MEMORY_HOOK_CACHE_OUTCOMES);
29
+ const SampleOutcomeSchema = z.enum(MEMORY_HOOK_SAMPLE_OUTCOMES);
30
+ const CountSchema = z.number().int().nonnegative();
31
+ const SemverSchema = z
32
+ .string()
33
+ .min(1)
34
+ .max(40)
35
+ .regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u);
36
+ export const MemoryHookSampleSchema = z
37
+ .object({
38
+ schema_version: z.literal(MEMORY_HOOK_SAMPLE_SCHEMA_VERSION),
39
+ recorded_at: IsoDateTimeSchema,
40
+ elapsed_ms: z.number().finite().int().nonnegative().max(60_000),
41
+ outcome: SampleOutcomeSchema,
42
+ embed_cache: CacheOutcomeSchema,
43
+ producer_version: SemverSchema,
44
+ })
45
+ .strict();
46
+ export const MemoryHookSamplingLeaseSchema = z
47
+ .object({
48
+ schema_version: z.literal(MEMORY_HOOK_SAMPLING_LEASE_SCHEMA_VERSION),
49
+ continuous_since: IsoDateTimeSchema,
50
+ expires_at: IsoDateTimeSchema,
51
+ })
52
+ .strict();
53
+ /** The samples directory below the user's existing Cockpit state directory. */
54
+ export const MEMORY_HOOK_SAMPLES_DIRECTORY_NAME = "memory-hook-samples";
55
+ export function memoryHookSamplesDirectory(homeDir) {
56
+ const paths = getUserLocalCockpitPaths(homeDir);
57
+ const separator = paths.state_dir.includes("\\") ? "\\" : "/";
58
+ return `${paths.state_dir}${separator}${MEMORY_HOOK_SAMPLES_DIRECTORY_NAME}`;
59
+ }
60
+ export const MEMORY_HOOK_HISTOGRAM_BIN_WIDTH_MS = 100;
61
+ export const MEMORY_HOOK_HISTOGRAM_LENGTH = 51;
62
+ /** A fresh [0,100), ... [4900,5000), [5000,infinity) histogram. */
63
+ export function blankHistogram() {
64
+ return Array.from({ length: MEMORY_HOOK_HISTOGRAM_LENGTH }, () => 0);
65
+ }
66
+ function validateHistogram(histogram) {
67
+ if (histogram.length !== MEMORY_HOOK_HISTOGRAM_LENGTH) {
68
+ throw new RangeError(`histogram must have ${MEMORY_HOOK_HISTOGRAM_LENGTH} bins`);
69
+ }
70
+ for (const count of histogram) {
71
+ if (!Number.isInteger(count) || count < 0) {
72
+ throw new RangeError("histogram counts must be non-negative integers");
73
+ }
74
+ }
75
+ }
76
+ /** Add one valid duration and return the same histogram for convenient chaining. */
77
+ export function addDuration(histogram, durationMs) {
78
+ validateHistogram(histogram);
79
+ if (!Number.isFinite(durationMs) || !Number.isInteger(durationMs) || durationMs < 0) {
80
+ throw new RangeError("duration must be a non-negative integer");
81
+ }
82
+ if (durationMs > 60_000) {
83
+ throw new RangeError("duration must be at most 60000 ms");
84
+ }
85
+ const bin = Math.min(Math.floor(durationMs / MEMORY_HOOK_HISTOGRAM_BIN_WIDTH_MS), MEMORY_HOOK_HISTOGRAM_LENGTH - 1);
86
+ histogram[bin] += 1;
87
+ return histogram;
88
+ }
89
+ /**
90
+ * Return the nearest-rank bin bounds. The result never interpolates between
91
+ * bins, and the open-ended final bin has no finite upper bound.
92
+ */
93
+ export function histogramPercentileBounds(histogram, percentile) {
94
+ validateHistogram(histogram);
95
+ if (!Number.isFinite(percentile) || percentile < 0 || percentile > 100) {
96
+ throw new RangeError("percentile must be between 0 and 100");
97
+ }
98
+ const samples = histogram.reduce((sum, count) => sum + count, 0);
99
+ if (samples === 0)
100
+ return null;
101
+ const rank = Math.max(1, Math.ceil((percentile / 100) * samples));
102
+ let cumulative = 0;
103
+ for (let index = 0; index < histogram.length; index += 1) {
104
+ cumulative += histogram[index] ?? 0;
105
+ if (cumulative >= rank) {
106
+ return {
107
+ lower_ms: index * MEMORY_HOOK_HISTOGRAM_BIN_WIDTH_MS,
108
+ upper_ms: index === MEMORY_HOOK_HISTOGRAM_LENGTH - 1
109
+ ? null
110
+ : (index + 1) * MEMORY_HOOK_HISTOGRAM_BIN_WIDTH_MS,
111
+ };
112
+ }
113
+ }
114
+ return null;
115
+ }
116
+ const OutcomeCountsSchema = z
117
+ .object({
118
+ printed: CountSchema,
119
+ empty: CountSchema,
120
+ timeouts: CountSchema,
121
+ failed: CountSchema,
122
+ skipped: CountSchema,
123
+ })
124
+ .strict();
125
+ const HistogramSchema = z
126
+ .array(CountSchema)
127
+ .length(MEMORY_HOOK_HISTOGRAM_LENGTH);
128
+ const DurationByCacheSchema = z
129
+ .object({
130
+ hit: HistogramSchema,
131
+ miss: HistogramSchema,
132
+ shared: HistogramSchema,
133
+ unknown: HistogramSchema,
134
+ })
135
+ .strict();
136
+ const ProducerVersionCountSchema = z
137
+ .object({
138
+ version: SemverSchema,
139
+ samples: CountSchema,
140
+ })
141
+ .strict();
142
+ export const MEMORY_HOOK_PERFORMANCE_REASONS = [
143
+ "no_samples",
144
+ "partial_window",
145
+ "lease_absent",
146
+ "lease_expired",
147
+ "lease_invalid",
148
+ "read_failed",
149
+ "read_limit",
150
+ "invalid_samples",
151
+ "incomplete_samples",
152
+ "unreadable_samples",
153
+ "cleanup_failed",
154
+ ];
155
+ const PerformanceReasonSchema = z.enum(MEMORY_HOOK_PERFORMANCE_REASONS);
156
+ export const MemoryHookPerformanceSchema = z
157
+ .object({
158
+ schema_version: z.literal(MEMORY_HOOK_PERFORMANCE_SCHEMA_VERSION),
159
+ window_start: IsoDateTimeSchema,
160
+ window_end: IsoDateTimeSchema,
161
+ sampling_since: IsoDateTimeSchema.nullable(),
162
+ samples: CountSchema,
163
+ outcomes: OutcomeCountsSchema,
164
+ duration_by_cache: DurationByCacheSchema,
165
+ producer_versions: z.array(ProducerVersionCountSchema).max(16),
166
+ invalid_samples: CountSchema,
167
+ incomplete_samples: CountSchema,
168
+ unreadable_samples: CountSchema,
169
+ capped: z.boolean(),
170
+ reasons: z.array(PerformanceReasonSchema).max(MEMORY_HOOK_PERFORMANCE_REASONS.length),
171
+ })
172
+ .strict()
173
+ .superRefine((value, context) => {
174
+ const outcomeTotal = Object.values(value.outcomes).reduce((sum, count) => sum + count, 0);
175
+ if (outcomeTotal !== value.samples) {
176
+ context.addIssue({
177
+ code: "custom",
178
+ path: ["outcomes"],
179
+ message: "outcome counts must sum to samples",
180
+ });
181
+ }
182
+ const histogramTotal = Object.values(value.duration_by_cache)
183
+ .flat()
184
+ .reduce((sum, count) => sum + count, 0);
185
+ if (histogramTotal !== value.samples) {
186
+ context.addIssue({
187
+ code: "custom",
188
+ path: ["duration_by_cache"],
189
+ message: "duration histograms must sum to samples",
190
+ });
191
+ }
192
+ const versionTotal = value.producer_versions.reduce((sum, item) => sum + item.samples, 0);
193
+ if (versionTotal !== value.samples) {
194
+ context.addIssue({
195
+ code: "custom",
196
+ path: ["producer_versions"],
197
+ message: "producer version counts must sum to samples",
198
+ });
199
+ }
200
+ const versions = value.producer_versions.map((item) => item.version);
201
+ if (new Set(versions).size !== versions.length) {
202
+ context.addIssue({
203
+ code: "custom",
204
+ path: ["producer_versions"],
205
+ message: "producer versions must be unique",
206
+ });
207
+ }
208
+ });
@@ -114,6 +114,47 @@ export declare const MemoryInstallReceiptSchema: z.ZodObject<{
114
114
  hook_printed_24h: z.ZodOptional<z.ZodNumber>;
115
115
  hook_failed_24h: z.ZodOptional<z.ZodNumber>;
116
116
  hook_stats_reason: z.ZodOptional<z.ZodString>;
117
+ hook_performance: z.ZodOptional<z.ZodObject<{
118
+ schema_version: z.ZodLiteral<"memory-hook-performance.v1">;
119
+ window_start: z.ZodString;
120
+ window_end: z.ZodString;
121
+ sampling_since: z.ZodNullable<z.ZodString>;
122
+ samples: z.ZodNumber;
123
+ outcomes: z.ZodObject<{
124
+ printed: z.ZodNumber;
125
+ empty: z.ZodNumber;
126
+ timeouts: z.ZodNumber;
127
+ failed: z.ZodNumber;
128
+ skipped: z.ZodNumber;
129
+ }, z.core.$strict>;
130
+ duration_by_cache: z.ZodObject<{
131
+ hit: z.ZodArray<z.ZodNumber>;
132
+ miss: z.ZodArray<z.ZodNumber>;
133
+ shared: z.ZodArray<z.ZodNumber>;
134
+ unknown: z.ZodArray<z.ZodNumber>;
135
+ }, z.core.$strict>;
136
+ producer_versions: z.ZodArray<z.ZodObject<{
137
+ version: z.ZodString;
138
+ samples: z.ZodNumber;
139
+ }, z.core.$strict>>;
140
+ invalid_samples: z.ZodNumber;
141
+ incomplete_samples: z.ZodNumber;
142
+ unreadable_samples: z.ZodNumber;
143
+ capped: z.ZodBoolean;
144
+ reasons: z.ZodArray<z.ZodEnum<{
145
+ no_samples: "no_samples";
146
+ partial_window: "partial_window";
147
+ lease_absent: "lease_absent";
148
+ lease_expired: "lease_expired";
149
+ lease_invalid: "lease_invalid";
150
+ read_failed: "read_failed";
151
+ read_limit: "read_limit";
152
+ invalid_samples: "invalid_samples";
153
+ incomplete_samples: "incomplete_samples";
154
+ unreadable_samples: "unreadable_samples";
155
+ cleanup_failed: "cleanup_failed";
156
+ }>>;
157
+ }, z.core.$strict>>;
117
158
  }, z.core.$strict>;
118
159
  export type MemoryInstallReceipt = z.infer<typeof MemoryInstallReceiptSchema>;
119
160
  /** Every piece is `ok`. The one question the board asks first. */
@@ -33,6 +33,7 @@
33
33
  */
34
34
  import { z } from "zod";
35
35
  import { IsoDateTimeSchema } from "./common.js";
36
+ import { MemoryHookPerformanceSchema } from "./memory-hook-performance.js";
36
37
  export const MEMORY_INSTALL_RECEIPT_SCHEMA_VERSION = "memory-install-receipt.v1";
37
38
  /**
38
39
  * What one piece of the installation is.
@@ -133,6 +134,8 @@ export const MemoryInstallReceiptSchema = z
133
134
  hook_failed_24h: z.number().int().min(0).optional(),
134
135
  /** Named when the counts are absent because the file could not be read. */
135
136
  hook_stats_reason: ReasonLabelSchema.optional(),
137
+ /** Observed ordinary invocations, not legacy floors or a full host trace. */
138
+ hook_performance: MemoryHookPerformanceSchema.optional(),
136
139
  })
137
140
  .strict();
138
141
  /** Every piece is `ok`. The one question the board asks first. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bli-cockpit/telemetry-core",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",