1
0

fixture.sql 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. -- Seed data for the dashboard's local checks: 12 machines over 10 days
  2. -- (2026-07-01 … 2026-07-10), small enough that every number on every panel can
  3. -- be worked out by hand from the events below and checked against the API.
  4. --
  5. -- npm run seed (writes the LOCAL .wrangler D1 — never the remote one)
  6. --
  7. -- Only the raw `events` rows are hand-authored. `machine_days`,
  8. -- `machine_first_seen` and the three `daily_*` rollups are DERIVED from them at
  9. -- the bottom of this file by the same aggregations the writers use in
  10. -- telemetry-worker/ (the ingest path and the nightly cron respectively), so the
  11. -- fixture can never drift into a state production could not produce.
  12. --
  13. -- The machines, and what each one does:
  14. --
  15. -- id first os arch ver ci installs indexes on uninstalls
  16. -- m01 07-01 darwin arm64 1.4.0 0 local 07-01, 07-02, 07-04
  17. -- m02 07-01 darwin arm64 1.4.0 0 global 07-01
  18. -- m03 07-01 linux x64 1.4.0 0 local 07-03
  19. -- m04 07-01 win32 x64 1.4.0 0 local never 07-06
  20. -- m05 07-02 darwin arm64 1.4.0 0 local 07-02
  21. -- m06 07-02 linux x64 1.4.1 0 local never 07-07
  22. -- m07 07-03 darwin x64 1.4.1 0 local 07-03
  23. -- m08 07-05 linux arm64 1.5.0 0 global 07-06
  24. -- m09 07-05 win32 x64 1.5.0 0 local 07-05, 07-07
  25. -- m10 07-08 darwin arm64 1.5.0 0 local 07-08
  26. -- m11 07-09 linux x64 1.5.0 0 local 07-10
  27. -- m12 07-09 linux x64 1.5.0 1 global 07-09 (CI runner)
  28. --
  29. -- m04 and m06 never index: they are the two machines the activation funnel is
  30. -- supposed to lose (12 installs → 10 activated → 83.3%). m12 is the one CI
  31. -- machine, so "production users" is 11 where "active machines" is 12.
  32. DELETE FROM daily_dim_counts;
  33. DELETE FROM daily_event_counts;
  34. DELETE FROM daily_machines;
  35. DELETE FROM machine_days;
  36. DELETE FROM machine_first_seen;
  37. DELETE FROM events;
  38. -- ---------------------------------------------------------------------------
  39. -- install — 12, one per machine on its first day
  40. -- ---------------------------------------------------------------------------
  41. INSERT INTO events (received_at, ts, day, event, machine_id, codegraph_version, os, arch, node_major, ci, schema_version, props)
  42. VALUES
  43. ('2026-07-01T09:00:00Z','2026-07-01T09:00:00Z','2026-07-01','install','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"scope":"local","kind":"fresh","targets":["claude","cursor"]}'),
  44. ('2026-07-01T09:05:00Z','2026-07-01T09:05:00Z','2026-07-01','install','00000000-0000-4000-8000-000000000002','1.4.0','darwin','arm64',22,0,2,'{"scope":"global","kind":"fresh","targets":["claude"]}'),
  45. ('2026-07-01T10:00:00Z','2026-07-01T10:00:00Z','2026-07-01','install','00000000-0000-4000-8000-000000000003','1.4.0','linux','x64',20,0,2,'{"scope":"local","kind":"fresh","targets":["codex"]}'),
  46. ('2026-07-01T11:00:00Z','2026-07-01T11:00:00Z','2026-07-01','install','00000000-0000-4000-8000-000000000004','1.4.0','win32','x64',22,0,2,'{"scope":"local","kind":"fresh","targets":["claude","opencode"]}'),
  47. ('2026-07-02T09:00:00Z','2026-07-02T09:00:00Z','2026-07-02','install','00000000-0000-4000-8000-000000000005','1.4.0','darwin','arm64',22,0,2,'{"scope":"local","kind":"fresh","targets":["claude"]}'),
  48. ('2026-07-02T14:00:00Z','2026-07-02T14:00:00Z','2026-07-02','install','00000000-0000-4000-8000-000000000006','1.4.1','linux','x64',20,0,2,'{"scope":"local","kind":"fresh","targets":["cursor"]}'),
  49. ('2026-07-03T08:00:00Z','2026-07-03T08:00:00Z','2026-07-03','install','00000000-0000-4000-8000-000000000007','1.4.1','darwin','x64',22,0,2,'{"scope":"local","kind":"upgrade","targets":["claude"]}'),
  50. ('2026-07-05T08:00:00Z','2026-07-05T08:00:00Z','2026-07-05','install','00000000-0000-4000-8000-000000000008','1.5.0','linux','arm64',22,0,2,'{"scope":"global","kind":"fresh","targets":["claude","codex"]}'),
  51. ('2026-07-05T09:00:00Z','2026-07-05T09:00:00Z','2026-07-05','install','00000000-0000-4000-8000-000000000009','1.5.0','win32','x64',22,0,2,'{"scope":"local","kind":"fresh","targets":["claude"]}'),
  52. ('2026-07-08T08:00:00Z','2026-07-08T08:00:00Z','2026-07-08','install','00000000-0000-4000-8000-000000000010','1.5.0','darwin','arm64',22,0,2,'{"scope":"local","kind":"fresh","targets":["cursor"]}'),
  53. ('2026-07-09T08:00:00Z','2026-07-09T08:00:00Z','2026-07-09','install','00000000-0000-4000-8000-000000000011','1.5.0','linux','x64',22,0,2,'{"scope":"local","kind":"fresh","targets":["claude"]}'),
  54. ('2026-07-09T08:30:00Z','2026-07-09T08:30:00Z','2026-07-09','install','00000000-0000-4000-8000-000000000012','1.5.0','linux','x64',22,1,2,'{"scope":"global","kind":"fresh","targets":["claude"]}');
  55. -- ---------------------------------------------------------------------------
  56. -- index — 13 runs
  57. -- languages typescript 7 · javascript 2 · python 2 · go 2 · rust 2 · csharp 2 · java 1 (18 rows)
  58. -- file_count_bucket <100 2 · 100-1k 5 · 1k-10k 4 · 10k+ 2
  59. -- duration_bucket <10s 5 · 10-60s 4 · 1-5m 2 · 5m+ 2
  60. -- ---------------------------------------------------------------------------
  61. INSERT INTO events (received_at, ts, day, event, machine_id, codegraph_version, os, arch, node_major, ci, schema_version, props)
  62. VALUES
  63. ('2026-07-01T09:10:00Z','2026-07-01T09:10:00Z','2026-07-01','index','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"languages":["typescript","javascript"],"file_count_bucket":"100-1k","duration_bucket":"<10s"}'),
  64. ('2026-07-01T09:20:00Z','2026-07-01T09:20:00Z','2026-07-01','index','00000000-0000-4000-8000-000000000002','1.4.0','darwin','arm64',22,0,2,'{"languages":["typescript"],"file_count_bucket":"<100","duration_bucket":"<10s"}'),
  65. ('2026-07-02T10:00:00Z','2026-07-02T10:00:00Z','2026-07-02','index','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"languages":["typescript","javascript"],"file_count_bucket":"100-1k","duration_bucket":"10-60s"}'),
  66. ('2026-07-02T11:00:00Z','2026-07-02T11:00:00Z','2026-07-02','index','00000000-0000-4000-8000-000000000005','1.4.0','darwin','arm64',22,0,2,'{"languages":["python"],"file_count_bucket":"1k-10k","duration_bucket":"10-60s"}'),
  67. ('2026-07-03T09:00:00Z','2026-07-03T09:00:00Z','2026-07-03','index','00000000-0000-4000-8000-000000000003','1.4.0','linux','x64',20,0,2,'{"languages":["go"],"file_count_bucket":"100-1k","duration_bucket":"<10s"}'),
  68. ('2026-07-03T10:00:00Z','2026-07-03T10:00:00Z','2026-07-03','index','00000000-0000-4000-8000-000000000007','1.4.1','darwin','x64',22,0,2,'{"languages":["typescript","rust"],"file_count_bucket":"10k+","duration_bucket":"5m+"}'),
  69. ('2026-07-04T10:00:00Z','2026-07-04T10:00:00Z','2026-07-04','index','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"languages":["typescript"],"file_count_bucket":"100-1k","duration_bucket":"<10s"}'),
  70. ('2026-07-05T09:30:00Z','2026-07-05T09:30:00Z','2026-07-05','index','00000000-0000-4000-8000-000000000009','1.5.0','win32','x64',22,0,2,'{"languages":["csharp"],"file_count_bucket":"1k-10k","duration_bucket":"1-5m"}'),
  71. ('2026-07-06T09:00:00Z','2026-07-06T09:00:00Z','2026-07-06','index','00000000-0000-4000-8000-000000000008','1.5.0','linux','arm64',22,0,2,'{"languages":["rust","go"],"file_count_bucket":"1k-10k","duration_bucket":"1-5m"}'),
  72. ('2026-07-07T09:00:00Z','2026-07-07T09:00:00Z','2026-07-07','index','00000000-0000-4000-8000-000000000009','1.5.0','win32','x64',22,0,2,'{"languages":["csharp"],"file_count_bucket":"1k-10k","duration_bucket":"10-60s"}'),
  73. ('2026-07-08T08:10:00Z','2026-07-08T08:10:00Z','2026-07-08','index','00000000-0000-4000-8000-000000000010','1.5.0','darwin','arm64',22,0,2,'{"languages":["typescript"],"file_count_bucket":"<100","duration_bucket":"<10s"}'),
  74. ('2026-07-09T09:00:00Z','2026-07-09T09:00:00Z','2026-07-09','index','00000000-0000-4000-8000-000000000012','1.5.0','linux','x64',22,1,2,'{"languages":["java"],"file_count_bucket":"10k+","duration_bucket":"5m+"}'),
  75. ('2026-07-10T09:00:00Z','2026-07-10T09:00:00Z','2026-07-10','index','00000000-0000-4000-8000-000000000011','1.5.0','linux','x64',22,0,2,'{"languages":["python","typescript"],"file_count_bucket":"100-1k","duration_bucket":"10-60s"}');
  76. -- ---------------------------------------------------------------------------
  77. -- uninstall — 2
  78. -- ---------------------------------------------------------------------------
  79. INSERT INTO events (received_at, ts, day, event, machine_id, codegraph_version, os, arch, node_major, ci, schema_version, props)
  80. VALUES
  81. ('2026-07-06T12:00:00Z','2026-07-06T12:00:00Z','2026-07-06','uninstall','00000000-0000-4000-8000-000000000004','1.4.0','win32','x64',22,0,2,'{"targets":["claude","opencode"]}'),
  82. ('2026-07-07T12:00:00Z','2026-07-07T12:00:00Z','2026-07-07','uninstall','00000000-0000-4000-8000-000000000006','1.4.1','linux','x64',20,0,2,'{"targets":["cursor"]}');
  83. -- ---------------------------------------------------------------------------
  84. -- usage_rollup — 5 rows, 85 calls (the `count` prop is summed, never the rows)
  85. -- codegraph_explore 82 · index 3 | Claude Code 70 · Cursor 12
  86. -- ---------------------------------------------------------------------------
  87. INSERT INTO events (received_at, ts, day, event, machine_id, codegraph_version, os, arch, node_major, ci, schema_version, props)
  88. VALUES
  89. ('2026-07-03T02:00:00Z','2026-07-02T12:00:00Z','2026-07-02','usage_rollup','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"kind":"mcp_tool","name":"codegraph_explore","count":40,"error_count":1,"client_name":"Claude Code"}'),
  90. ('2026-07-04T02:00:00Z','2026-07-03T12:00:00Z','2026-07-03','usage_rollup','00000000-0000-4000-8000-000000000001','1.4.0','darwin','arm64',22,0,2,'{"kind":"mcp_tool","name":"codegraph_explore","count":25,"client_name":"Claude Code"}'),
  91. ('2026-07-04T02:00:00Z','2026-07-03T12:00:00Z','2026-07-03','usage_rollup','00000000-0000-4000-8000-000000000005','1.4.0','darwin','arm64',22,0,2,'{"kind":"cli_command","name":"index","count":3}'),
  92. ('2026-07-07T02:00:00Z','2026-07-06T12:00:00Z','2026-07-06','usage_rollup','00000000-0000-4000-8000-000000000009','1.5.0','win32','x64',22,0,2,'{"kind":"mcp_tool","name":"codegraph_explore","count":12,"client_name":"Cursor"}'),
  93. ('2026-07-11T02:00:00Z','2026-07-10T12:00:00Z','2026-07-10','usage_rollup','00000000-0000-4000-8000-000000000011','1.5.0','linux','x64',22,0,2,'{"kind":"mcp_tool","name":"codegraph_explore","count":5,"client_name":"Claude Code"}');
  94. -- ---------------------------------------------------------------------------
  95. -- Derived: what the ingest worker writes on every batch
  96. -- ---------------------------------------------------------------------------
  97. -- prod is 0 only when EVERY event a machine sent that day carried ci = 1, which
  98. -- is what makes m12 the only non-production machine-day.
  99. INSERT INTO machine_days (machine_id, day, prod)
  100. SELECT machine_id, day, max(CASE WHEN ci = 1 THEN 0 ELSE 1 END) FROM events GROUP BY machine_id, day;
  101. INSERT INTO machine_first_seen (machine_id, first_day)
  102. SELECT machine_id, min(day) FROM events GROUP BY machine_id;
  103. -- ---------------------------------------------------------------------------
  104. -- Derived: what the nightly cron writes
  105. -- ---------------------------------------------------------------------------
  106. -- These mirror ROLLUP_STATEMENTS in telemetry-worker/src/rollup.ts, with the
  107. -- single-day filter dropped so one pass seeds the whole fixture range.
  108. INSERT INTO daily_machines (day, machines, prod_machines)
  109. SELECT day, count(*), coalesce(sum(prod), 0) FROM machine_days GROUP BY day;
  110. INSERT INTO daily_event_counts (day, event, count, machines)
  111. SELECT day, event,
  112. CASE WHEN event = 'usage_rollup'
  113. THEN sum(coalesce(json_extract(props, '$.count'), 0))
  114. ELSE count(*) END,
  115. count(DISTINCT machine_id)
  116. FROM events GROUP BY day, event;
  117. -- Envelope dimensions — carried by every event.
  118. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  119. SELECT day, event, 'os', CAST(os AS TEXT),
  120. CASE WHEN event = 'usage_rollup' THEN sum(coalesce(json_extract(props, '$.count'), 0)) ELSE count(*) END,
  121. count(DISTINCT machine_id)
  122. FROM events WHERE os IS NOT NULL AND os <> '' GROUP BY day, event, os;
  123. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  124. SELECT day, event, 'arch', CAST(arch AS TEXT),
  125. CASE WHEN event = 'usage_rollup' THEN sum(coalesce(json_extract(props, '$.count'), 0)) ELSE count(*) END,
  126. count(DISTINCT machine_id)
  127. FROM events WHERE arch IS NOT NULL AND arch <> '' GROUP BY day, event, arch;
  128. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  129. SELECT day, event, 'codegraph_version', CAST(codegraph_version AS TEXT),
  130. CASE WHEN event = 'usage_rollup' THEN sum(coalesce(json_extract(props, '$.count'), 0)) ELSE count(*) END,
  131. count(DISTINCT machine_id)
  132. FROM events WHERE codegraph_version IS NOT NULL AND codegraph_version <> '' GROUP BY day, event, codegraph_version;
  133. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  134. SELECT day, event, 'node_major', CAST(node_major AS TEXT),
  135. CASE WHEN event = 'usage_rollup' THEN sum(coalesce(json_extract(props, '$.count'), 0)) ELSE count(*) END,
  136. count(DISTINCT machine_id)
  137. FROM events WHERE node_major IS NOT NULL GROUP BY day, event, node_major;
  138. -- Event-specific scalar props.
  139. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  140. SELECT day, event, 'file_count_bucket', CAST(json_extract(props, '$.file_count_bucket') AS TEXT), count(*), count(DISTINCT machine_id)
  141. FROM events WHERE event = 'index' AND json_extract(props, '$.file_count_bucket') IS NOT NULL
  142. GROUP BY day, event, json_extract(props, '$.file_count_bucket');
  143. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  144. SELECT day, event, 'duration_bucket', CAST(json_extract(props, '$.duration_bucket') AS TEXT), count(*), count(DISTINCT machine_id)
  145. FROM events WHERE event = 'index' AND json_extract(props, '$.duration_bucket') IS NOT NULL
  146. GROUP BY day, event, json_extract(props, '$.duration_bucket');
  147. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  148. SELECT day, event, 'scope', CAST(json_extract(props, '$.scope') AS TEXT), count(*), count(DISTINCT machine_id)
  149. FROM events WHERE event = 'install' AND json_extract(props, '$.scope') IS NOT NULL
  150. GROUP BY day, event, json_extract(props, '$.scope');
  151. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  152. SELECT day, event, 'kind', CAST(json_extract(props, '$.kind') AS TEXT),
  153. CASE WHEN event = 'usage_rollup' THEN sum(coalesce(json_extract(props, '$.count'), 0)) ELSE count(*) END,
  154. count(DISTINCT machine_id)
  155. FROM events WHERE event IN ('install', 'usage_rollup') AND json_extract(props, '$.kind') IS NOT NULL
  156. GROUP BY day, event, json_extract(props, '$.kind');
  157. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  158. SELECT day, event, 'name', CAST(json_extract(props, '$.name') AS TEXT),
  159. sum(coalesce(json_extract(props, '$.count'), 0)), count(DISTINCT machine_id)
  160. FROM events WHERE event = 'usage_rollup' AND json_extract(props, '$.name') IS NOT NULL
  161. GROUP BY day, event, json_extract(props, '$.name');
  162. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  163. SELECT day, event, 'client_name', CAST(json_extract(props, '$.client_name') AS TEXT),
  164. sum(coalesce(json_extract(props, '$.count'), 0)), count(DISTINCT machine_id)
  165. FROM events WHERE event = 'usage_rollup' AND json_extract(props, '$.client_name') IS NOT NULL
  166. GROUP BY day, event, json_extract(props, '$.client_name');
  167. -- Array props — one row per element, so a TypeScript+Go repo counts under both.
  168. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  169. SELECT e.day, e.event, 'language', CAST(j.value AS TEXT), count(*), count(DISTINCT e.machine_id)
  170. FROM events e, json_each(e.props, '$.languages') j
  171. WHERE e.event = 'index' AND j.value <> ''
  172. GROUP BY e.day, e.event, j.value;
  173. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  174. SELECT e.day, e.event, 'target', CAST(j.value AS TEXT), count(*), count(DISTINCT e.machine_id)
  175. FROM events e, json_each(e.props, '$.targets') j
  176. WHERE e.event IN ('install', 'uninstall') AND j.value <> ''
  177. GROUP BY e.day, e.event, j.value;
  178. -- Errors per tool: count is errors, machines is the machines that saw one.
  179. INSERT INTO daily_dim_counts (day, event, dim, value, count, machines)
  180. SELECT day, event, 'name_error', CAST(json_extract(props, '$.name') AS TEXT),
  181. sum(json_extract(props, '$.error_count')), count(DISTINCT machine_id)
  182. FROM events
  183. WHERE event = 'usage_rollup' AND json_extract(props, '$.name') IS NOT NULL
  184. AND coalesce(json_extract(props, '$.error_count'), 0) > 0
  185. GROUP BY day, event, json_extract(props, '$.name');