1import * as Axiom from "@alchemy.run/axiom";
2import * as Output from "alchemy/Output";
3import * as Effect from "effect/Effect";
4import { cacheName } from "./resources.ts";
5
6// Native summaries may be observed by nested launchers and retried after a lost response.
7// Deduplicate before summing; task runtime is a compute proxy, not measured CPU or critical-path time.
8export const savingsQuery = (
9 dataset: string,
10 group?: "developer" | "host" | "ci",
11 lifetime = false,
12) =>
13 [
14 `['${dataset}']`,
15 `| where name == '${lifetime ? "TaskCache.lifetime" : "TaskCache.summary"}'`,
16 `| extend a = ['attributes.custom']`,
17 `| extend event_id = tostring(a['cache.event_id']), developer = tostring(a['developer.id']), host = tostring(['attributes.host.name']), ci = tobool(a['ci']), recorded_at = tolong(a['cache.recorded_at']), unspecified_ms = coalesce(tolong(a['cache.unspecified_saved_ms']), 0), unspecified_hits = coalesce(tolong(a['cache.unspecified_hits']), 0), local_ms = tolong(a['cache.local_saved_ms']), remote_ms = tolong(a['cache.remote_saved_ms']), local_hits = tolong(a['cache.local_hits']), remote_hits = tolong(a['cache.remote_hits']), executed = tolong(a['cache.executed']), restore_failures = tolong(a['cache.restore_failures'])`,
18 `| summarize arg_max(_time, unspecified_ms, unspecified_hits, local_ms, remote_ms, local_hits, remote_hits, executed, restore_failures${lifetime ? "" : ", developer, host, ci, recorded_at"}) by ${lifetime ? "developer, host, ci, platform = tostring(a['host.os']), arch = tostring(['attributes.host.arch'])" : "event_id"}`,
19 ...(!lifetime ? ["| extend _time = unixtime_milliseconds_todatetime(recorded_at)"] : []),
20 `| where local_hits + remote_hits + unspecified_hits + executed + restore_failures > 0`,
21 `| summarize saved_task_hours = sum(local_ms + remote_ms + unspecified_ms) / 3600000.0, remote_saved_hours = sum(remote_ms) / 3600000.0, local_saved_hours = sum(local_ms) / 3600000.0, unspecified_saved_hours = sum(unspecified_ms) / 3600000.0, unspecified_hits = sum(unspecified_hits), local_hits = sum(local_hits), remote_hits = sum(remote_hits), executed = sum(executed), restore_failures = sum(restore_failures)${group ? ` by ${group}` : ""}`,
22 ].join("\n");
23
24const summaryRows = (dataset: string) => savingsQuery(dataset).split("\n").slice(0, -1).join("\n");
25
26// One row per native-client install report (scripts/mobile-native-client.ts), deduplicated by report id.
27const nativeInstalls = (dataset: string) =>
28 [
29 `['${dataset}']`,
30 `| where name == 'TaskCache.task'`,
31 `| extend a = ['attributes.custom']`,
32 `| where tostring(a['task.package']) == '@t3tools/mobile' and tostring(a['task.name']) startswith 'native-client'`,
33 `| extend event_id = tostring(a['cache.event_id']), task = tostring(a['task.name']), source = tostring(a['cache.source']), saved_ms = tolong(a['cache.saved_ms']), host = tostring(['attributes.host.name']), developer = tostring(a['developer.id'])`,
34 `| summarize arg_max(_time, task, source, saved_ms, host, developer) by event_id`,
35 ].join("\n");
36const nativeCounts =
37 "local = countif(source == 'local'), remote = countif(source == 'remote'), built = countif(source == 'executed'), failed = countif(source == 'failed')";
38
39export const Observability = Effect.gen(function* () {
40 const name = yield* cacheName;
41 const traces = yield* Axiom.Dataset("CacheTraces", {
42 name: `${name}-traces`,
43 kind: "otel:traces:v1",
44 description: "Shared task cache: service traces and unsampled native task savings reports.",
45 retentionDays: 30,
46 useRetentionPeriod: true,
47 });
48 const token = yield* Axiom.ApiToken("CacheIngestToken", {
49 name: `${name}-otel-ingest`,
50 datasetCapabilities: Output.map(traces.name, (dataset) => ({
51 [dataset]: { ingest: ["create" as const] },
52 })),
53 });
54 const charts = [
55 {
56 id: "total",
57 name: "⏳ Task hours given back · lifetime",
58 type: "Statistic",
59 x: 0,
60 y: 0,
61 w: 3,
62 h: 3,
63 query: (dataset: string) =>
64 `${savingsQuery(dataset, undefined, true)}\n| project saved_task_hours`,
65 },
66 {
67 id: "remote",
68 name: "🌍 Remote hours shared · lifetime",
69 type: "Statistic",
70 x: 3,
71 y: 0,
72 w: 3,
73 h: 3,
74 query: (dataset: string) =>
75 `${savingsQuery(dataset, undefined, true)}\n| project remote_saved_hours`,
76 },
77 {
78 id: "hit-rate",
79 name: "🎯 Cache hit rate · lifetime (%)",
80 type: "Statistic",
81 x: 6,
82 y: 0,
83 w: 3,
84 h: 3,
85 query: (dataset: string) =>
86 `${savingsQuery(dataset, undefined, true)}\n| project hit_rate = round(100.0 * (local_hits + remote_hits + unspecified_hits) / (local_hits + remote_hits + unspecified_hits + executed), 1)`,
87 },
88 {
89 id: "skipped",
90 name: "⚡ Tasks we skipped · lifetime",
91 type: "Statistic",
92 x: 9,
93 y: 0,
94 w: 3,
95 h: 3,
96 query: (dataset: string) =>
97 `${savingsQuery(dataset, undefined, true)}\n| project cached_tasks = local_hits + remote_hits + unspecified_hits`,
98 },
99 {
100 id: "savings-trend",
101 name: "📈 Minutes given back over time",
102 type: "TimeSeries",
103 x: 0,
104 y: 3,
105 w: 8,
106 h: 5,
107 query: (dataset: string) =>
108 `${summaryRows(dataset)}\n| summarize local_minutes = sum(local_ms) / 60000.0, remote_minutes = sum(remote_ms) / 60000.0, unspecified_minutes = sum(unspecified_ms) / 60000.0 by bin_auto(_time)`,
109 },
110 {
111 id: "developer",
112 name: "🏆 Who is saving the most?",
113 type: "Pie",
114 x: 8,
115 y: 3,
116 w: 4,
117 h: 5,
118 query: (dataset: string) =>
119 `${savingsQuery(dataset, "developer", true)}\n| project developer, saved_task_hours\n| order by saved_task_hours desc`,
120 },
121 {
122 id: "tasks-trend",
123 name: "🔥 Cache hits vs actual execution",
124 type: "TimeSeries",
125 x: 0,
126 y: 8,
127 w: 8,
128 h: 5,
129 query: (dataset: string) =>
130 `${summaryRows(dataset)}\n| summarize local_hits = sum(local_hits), remote_hits = sum(remote_hits), unspecified_hits = sum(unspecified_hits), executed = sum(executed) by bin_auto(_time)`,
131 },
132 {
133 id: "host",
134 name: "🖥️ The machine leaderboard",
135 type: "Pie",
136 x: 8,
137 y: 8,
138 w: 4,
139 h: 5,
140 query: (dataset: string) =>
141 `${savingsQuery(dataset, "host", true)}\n| project host, saved_task_hours\n| order by saved_task_hours desc`,
142 },
143 {
144 id: "leaderboard",
145 name: "🏅 Developer scorecard · lifetime",
146 type: "Table",
147 x: 0,
148 y: 13,
149 w: 8,
150 h: 4,
151 query: (dataset: string) =>
152 `${savingsQuery(dataset, "developer", true)}\n| project developer, saved_task_hours, remote_saved_hours, cached_tasks = local_hits + remote_hits + unspecified_hits, executed\n| order by saved_task_hours desc`,
153 },
154 {
155 id: "ci",
156 name: "🤖 CI vs developer machines · hours saved",
157 type: "Pie",
158 x: 8,
159 y: 13,
160 w: 4,
161 h: 4,
162 query: (dataset: string) =>
163 `${savingsQuery(dataset, "ci", true)}\n| summarize saved_task_hours = sum(saved_task_hours) by environment = iff(ci, "CI", "Developer machines")`,
164 },
165 {
166 id: "native-hit-rate",
167 name: "📱 Native client hit rate (%)",
168 type: "Statistic",
169 x: 0,
170 y: 17,
171 w: 3,
172 h: 3,
173 query: (dataset: string) =>
174 `${nativeInstalls(dataset)}\n| summarize ${nativeCounts}\n| project hit_rate = round(100.0 * (local + remote) / (local + remote + built), 1)`,
175 },
176 {
177 id: "native-saved",
178 name: "📱 Native build hours saved",
179 type: "Statistic",
180 x: 3,
181 y: 17,
182 w: 3,
183 h: 3,
184 query: (dataset: string) =>
185 `${nativeInstalls(dataset)}\n| summarize build_hours_saved = round(sum(saved_ms) / 3600000.0, 1)`,
186 },
187 {
188 id: "native-builds",
189 name: "📱 Native builds (cache misses)",
190 type: "Statistic",
191 x: 6,
192 y: 17,
193 w: 3,
194 h: 3,
195 query: (dataset: string) =>
196 `${nativeInstalls(dataset)}\n| summarize builds = countif(source == 'executed')`,
197 },
198 {
199 id: "native-failures",
200 name: "📱 Native install failures",
201 type: "Statistic",
202 x: 9,
203 y: 17,
204 w: 3,
205 h: 3,
206 query: (dataset: string) =>
207 `${nativeInstalls(dataset)}\n| summarize failures = countif(source == 'failed')`,
208 },
209 {
210 id: "native-trend",
211 name: "📱 Native installs: local, shared, built, failed",
212 type: "TimeSeries",
213 x: 0,
214 y: 20,
215 w: 8,
216 h: 5,
217 query: (dataset: string) =>
218 `${nativeInstalls(dataset)}\n| summarize ${nativeCounts} by bin_auto(_time)`,
219 },
220 {
221 id: "native-host",
222 name: "📱 Native installs by machine",
223 type: "Pie",
224 x: 8,
225 y: 20,
226 w: 4,
227 h: 5,
228 query: (dataset: string) =>
229 `${nativeInstalls(dataset)}\n| summarize installs = count() by host\n| order by installs desc`,
230 },
231 {
232 id: "native-platforms",
233 name: "📱 Native clients by platform",
234 type: "Table",
235 x: 0,
236 y: 25,
237 w: 8,
238 h: 4,
239 query: (dataset: string) =>
240 `${nativeInstalls(dataset)}\n| summarize ${nativeCounts}, hours_saved = round(sum(saved_ms) / 3600000.0, 2) by task\n| extend hit_rate = round(100.0 * (local + remote) / (local + remote + built), 1)\n| order by local + remote + built desc`,
241 },
242 {
243 id: "native-shared",
244 name: "📱 Shared cache downloads: hit vs miss",
245 type: "TimeSeries",
246 x: 8,
247 y: 25,
248 w: 4,
249 h: 4,
250 query: (dataset: string) =>
251 `['${dataset}']\n| where name == 'NativeClients.handle' and tostring(['attributes.custom']['native.operation']) == 'download'\n| extend result = tostring(['attributes.custom']['native.result'])\n| summarize hits = countif(result == 'hit'), misses = countif(result == 'miss') by bin_auto(_time)`,
252 },
253 ] as const;
254 for (const chart of charts) {
255 yield* Axiom.View(`CacheSavings-${chart.id}`, {
256 name: `${name}-${chart.id}-savings`,
257 description: chart.name,
258 datasets: [traces.name],
259 aplQuery: Output.map(traces.name, chart.query),
260 });
261 }
262 const dashboard = yield* Axiom.Dashboard("CacheSavingsDashboard", {
263 dashboard: {
264 name: "⚡ Task Cache · Time Back",
265 owner: "X-AXIOM-EVERYONE",
266 schemaVersion: 2,
267 refreshTime: 60,
268 description:
269 "Avoided task execution time, not CPU seconds or elapsed developer time. Local and remote hits; deduplicated native Vite+ summaries. Lifetime counters are retained in D1 and refreshed hourly. Raw traces have 30-day retention.",
270 timeWindowStart: "qr-now-30d",
271 timeWindowEnd: "qr-now",
272 charts: charts.map((chart) => {
273 const common = {
274 id: chart.id,
275 name: chart.name,
276 query: { apl: Output.map(traces.name, chart.query) },
277 };
278 switch (chart.type) {
279 case "Statistic":
280 return { ...common, type: "Statistic" as const };
281 case "TimeSeries":
282 return {
283 ...common,
284 type: "TimeSeries" as const,
285 query: {
286 ...common.query,
287 queryOptions: {
288 timeSeriesVariant: chart.id === "savings-trend" ? "area" : "bars",
289 displayNull: "zero",
290 overlayCharts: "true",
291 },
292 },
293 };
294 case "Pie":
295 return { ...common, type: "Pie" as const };
296 case "Table":
297 return { ...common, type: "Table" as const };
298 }
299 }),
300 layout: charts.map(({ id, x, y, w, h }) => ({ i: id, x, y, w, h })),
301 },
302 });
303 return { traces, token, dashboard };
304});