testerkit 0.4.0__py3-none-any.whl

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.
Files changed (521) hide show
  1. testerkit/__init__.py +68 -0
  2. testerkit/_docs/_assets/operator-ui/channels/table.png +0 -0
  3. testerkit/_docs/_assets/operator-ui/dashboard/runs.png +0 -0
  4. testerkit/_docs/_assets/operator-ui/dashboard/stations.png +0 -0
  5. testerkit/_docs/_assets/operator-ui/events/filters.png +0 -0
  6. testerkit/_docs/_assets/operator-ui/events/table.png +0 -0
  7. testerkit/_docs/_assets/operator-ui/explore/chart.png +0 -0
  8. testerkit/_docs/_assets/operator-ui/explore/filters.png +0 -0
  9. testerkit/_docs/_assets/operator-ui/explore/plot-controls.png +0 -0
  10. testerkit/_docs/_assets/operator-ui/files/table.png +0 -0
  11. testerkit/_docs/_assets/operator-ui/launch/form.png +0 -0
  12. testerkit/_docs/_assets/operator-ui/metrics/filters.png +0 -0
  13. testerkit/_docs/_assets/operator-ui/metrics/pareto.png +0 -0
  14. testerkit/_docs/_assets/operator-ui/metrics/ppk.png +0 -0
  15. testerkit/_docs/_assets/operator-ui/metrics/yield.png +0 -0
  16. testerkit/_docs/_assets/operator-ui/results/detail-header.png +0 -0
  17. testerkit/_docs/_assets/operator-ui/results/detail-measurements.png +0 -0
  18. testerkit/_docs/_assets/operator-ui/results/detail-overview.png +0 -0
  19. testerkit/_docs/_assets/operator-ui/results/detail-steps.png +0 -0
  20. testerkit/_docs/_assets/operator-ui/results/stats.png +0 -0
  21. testerkit/_docs/_assets/operator-ui/results/table.png +0 -0
  22. testerkit/_docs/_assets/operator-ui/tour/designer.png +0 -0
  23. testerkit/_docs/_assets/operator-ui/tour/docs.png +0 -0
  24. testerkit/_docs/_assets/operator-ui/tour/fixtures.png +0 -0
  25. testerkit/_docs/_assets/operator-ui/tour/instruments.png +0 -0
  26. testerkit/_docs/_assets/operator-ui/tour/parts.png +0 -0
  27. testerkit/_docs/_assets/operator-ui/tour/profiles.png +0 -0
  28. testerkit/_docs/_assets/operator-ui/tour/stations.png +0 -0
  29. testerkit/_docs/_assets/operator-ui/tour/tests.png +0 -0
  30. testerkit/_docs/_assets/operator-ui/tour/uuts.png +0 -0
  31. testerkit/_docs/concepts/configuration/capabilities.md +447 -0
  32. testerkit/_docs/concepts/configuration/fixtures.md +335 -0
  33. testerkit/_docs/concepts/configuration/index.md +14 -0
  34. testerkit/_docs/concepts/configuration/parts.md +276 -0
  35. testerkit/_docs/concepts/configuration/stations.md +214 -0
  36. testerkit/_docs/concepts/data/data-stores.md +199 -0
  37. testerkit/_docs/concepts/data/event-log.md +185 -0
  38. testerkit/_docs/concepts/data/event-sourcing.md +76 -0
  39. testerkit/_docs/concepts/data/flight-streaming.md +58 -0
  40. testerkit/_docs/concepts/data/index.md +17 -0
  41. testerkit/_docs/concepts/data/sessions.md +78 -0
  42. testerkit/_docs/concepts/data/three-verbs.md +260 -0
  43. testerkit/_docs/concepts/execution/index.md +13 -0
  44. testerkit/_docs/concepts/execution/outcomes.md +199 -0
  45. testerkit/_docs/concepts/execution/step-hierarchy.md +170 -0
  46. testerkit/_docs/concepts/execution/step-manifest.md +115 -0
  47. testerkit/_docs/concepts/index.md +40 -0
  48. testerkit/_docs/concepts/overview/ai-integration.md +57 -0
  49. testerkit/_docs/concepts/overview/architecture.md +357 -0
  50. testerkit/_docs/concepts/overview/index.md +14 -0
  51. testerkit/_docs/concepts/overview/platform-vs-framework.md +147 -0
  52. testerkit/_docs/concepts/overview/pytest.md +53 -0
  53. testerkit/_docs/concepts/overview/tiers.md +46 -0
  54. testerkit/_docs/how-to/catalog/datasheet-to-test.md +169 -0
  55. testerkit/_docs/how-to/catalog/index.md +11 -0
  56. testerkit/_docs/how-to/configuration/configuring-stations.md +364 -0
  57. testerkit/_docs/how-to/configuration/custom-drivers.md +484 -0
  58. testerkit/_docs/how-to/configuration/index.md +13 -0
  59. testerkit/_docs/how-to/configuration/mock-mode.md +342 -0
  60. testerkit/_docs/how-to/data/benchmarking.md +120 -0
  61. testerkit/_docs/how-to/data/capture-an-artifact.md +84 -0
  62. testerkit/_docs/how-to/data/capture-waveform.md +110 -0
  63. testerkit/_docs/how-to/data/choosing-a-channel-verb.md +108 -0
  64. testerkit/_docs/how-to/data/compare-runs.md +120 -0
  65. testerkit/_docs/how-to/data/export-results.md +104 -0
  66. testerkit/_docs/how-to/data/find-flaky-tests.md +108 -0
  67. testerkit/_docs/how-to/data/grafana-dashboards.md +148 -0
  68. testerkit/_docs/how-to/data/index.md +23 -0
  69. testerkit/_docs/how-to/data/mcp-debug-failures.md +125 -0
  70. testerkit/_docs/how-to/data/mcp-query-runs.md +120 -0
  71. testerkit/_docs/how-to/data/querying-channels.md +117 -0
  72. testerkit/_docs/how-to/data/querying-events.md +85 -0
  73. testerkit/_docs/how-to/data/stream-live-channel.md +134 -0
  74. testerkit/_docs/how-to/execution/custom-operator-ui.md +136 -0
  75. testerkit/_docs/how-to/execution/index.md +21 -0
  76. testerkit/_docs/how-to/execution/limits.md +193 -0
  77. testerkit/_docs/how-to/execution/managing-sessions.md +100 -0
  78. testerkit/_docs/how-to/execution/multi-uut-testing.md +211 -0
  79. testerkit/_docs/how-to/execution/operator-prompts.md +151 -0
  80. testerkit/_docs/how-to/execution/profiles.md +304 -0
  81. testerkit/_docs/how-to/execution/spec-driven-testing.md +169 -0
  82. testerkit/_docs/how-to/execution/test-context.md +212 -0
  83. testerkit/_docs/how-to/execution/traceability.md +252 -0
  84. testerkit/_docs/how-to/execution/vector-expansion.md +394 -0
  85. testerkit/_docs/how-to/execution/writing-tests.md +363 -0
  86. testerkit/_docs/how-to/index.md +59 -0
  87. testerkit/_docs/how-to/overview/index.md +11 -0
  88. testerkit/_docs/how-to/overview/mcp-integration.md +168 -0
  89. testerkit/_docs/how-to/overview/operator-ui-tour.md +234 -0
  90. testerkit/_docs/integration/data/grafana.md +162 -0
  91. testerkit/_docs/integration/data/index.md +15 -0
  92. testerkit/_docs/integration/data/lakehouse-import.md +226 -0
  93. testerkit/_docs/integration/data/logging.md +131 -0
  94. testerkit/_docs/integration/data/results-api.md +51 -0
  95. testerkit/_docs/integration/index.md +20 -0
  96. testerkit/_docs/integration/runtime/harness.md +281 -0
  97. testerkit/_docs/integration/runtime/index.md +13 -0
  98. testerkit/_docs/integration/runtime/instruments.md +284 -0
  99. testerkit/_docs/integration/runtime/pytest-existing.md +315 -0
  100. testerkit/_docs/reference/catalog/cookbook.md +389 -0
  101. testerkit/_docs/reference/catalog/index.md +11 -0
  102. testerkit/_docs/reference/catalog/schema.md +375 -0
  103. testerkit/_docs/reference/cli.md +660 -0
  104. testerkit/_docs/reference/configuration.md +406 -0
  105. testerkit/_docs/reference/data/channels-schema.md +145 -0
  106. testerkit/_docs/reference/data/event-types.md +554 -0
  107. testerkit/_docs/reference/data/events-schema.md +120 -0
  108. testerkit/_docs/reference/data/files-schema.md +141 -0
  109. testerkit/_docs/reference/data/index.md +18 -0
  110. testerkit/_docs/reference/data/models.md +2229 -0
  111. testerkit/_docs/reference/data/outputs.md +82 -0
  112. testerkit/_docs/reference/data/parquet-schema.md +529 -0
  113. testerkit/_docs/reference/data/performance-limits.md +224 -0
  114. testerkit/_docs/reference/data/query-api.md +247 -0
  115. testerkit/_docs/reference/index.md +69 -0
  116. testerkit/_docs/reference/operator-ui/channels/detail.md +82 -0
  117. testerkit/_docs/reference/operator-ui/channels/list.md +70 -0
  118. testerkit/_docs/reference/operator-ui/dashboard.md +87 -0
  119. testerkit/_docs/reference/operator-ui/designer.md +167 -0
  120. testerkit/_docs/reference/operator-ui/events.md +89 -0
  121. testerkit/_docs/reference/operator-ui/files.md +74 -0
  122. testerkit/_docs/reference/operator-ui/fixtures.md +100 -0
  123. testerkit/_docs/reference/operator-ui/instruments.md +126 -0
  124. testerkit/_docs/reference/operator-ui/launch.md +79 -0
  125. testerkit/_docs/reference/operator-ui/live.md +102 -0
  126. testerkit/_docs/reference/operator-ui/measurements.md +159 -0
  127. testerkit/_docs/reference/operator-ui/metrics.md +217 -0
  128. testerkit/_docs/reference/operator-ui/parts.md +98 -0
  129. testerkit/_docs/reference/operator-ui/profiles.md +103 -0
  130. testerkit/_docs/reference/operator-ui/results/detail.md +214 -0
  131. testerkit/_docs/reference/operator-ui/results/list.md +106 -0
  132. testerkit/_docs/reference/operator-ui/stations.md +98 -0
  133. testerkit/_docs/reference/operator-ui/tests.md +173 -0
  134. testerkit/_docs/reference/operator-ui/uuts.md +67 -0
  135. testerkit/_docs/reference/overview/index.md +11 -0
  136. testerkit/_docs/reference/overview/pytest-native.md +142 -0
  137. testerkit/_docs/reference/overview/skills.md +177 -0
  138. testerkit/_docs/reference/pytest/fixtures.md +342 -0
  139. testerkit/_docs/reference/pytest/index.md +12 -0
  140. testerkit/_docs/reference/pytest/markers.md +257 -0
  141. testerkit/_docs/reference/runtime/api.md +246 -0
  142. testerkit/_docs/reference/runtime/client.md +280 -0
  143. testerkit/_docs/reference/runtime/connect.md +140 -0
  144. testerkit/_docs/reference/runtime/index.md +13 -0
  145. testerkit/_docs/tutorial/01-first-test.md +113 -0
  146. testerkit/_docs/tutorial/02-mock-instruments.md +88 -0
  147. testerkit/_docs/tutorial/03-fixtures.md +169 -0
  148. testerkit/_docs/tutorial/04-limits.md +139 -0
  149. testerkit/_docs/tutorial/05-configuration.md +194 -0
  150. testerkit/_docs/tutorial/06-specifications.md +273 -0
  151. testerkit/_docs/tutorial/07-real-instruments.md +245 -0
  152. testerkit/_docs/tutorial/08-capabilities.md +223 -0
  153. testerkit/_docs/tutorial/09-production.md +374 -0
  154. testerkit/_docs/tutorial/10-live-monitoring.md +156 -0
  155. testerkit/_docs/tutorial/11-waveforms-and-evidence.md +169 -0
  156. testerkit/_docs/tutorial/12-continuous-monitoring.md +145 -0
  157. testerkit/_docs/tutorial/13-parallel-testing.md +233 -0
  158. testerkit/_docs/tutorial/index.md +61 -0
  159. testerkit/_docs/tutorial/quickstart.md +282 -0
  160. testerkit/analysis/__init__.py +9 -0
  161. testerkit/analysis/_common.py +24 -0
  162. testerkit/analysis/measurement_facets.py +524 -0
  163. testerkit/analysis/measurements_query.py +1458 -0
  164. testerkit/analysis/metrics.py +389 -0
  165. testerkit/analysis/runs_query.py +434 -0
  166. testerkit/analysis/steps_query.py +413 -0
  167. testerkit/api/__init__.py +6 -0
  168. testerkit/api/_mime.py +71 -0
  169. testerkit/api/app.py +1171 -0
  170. testerkit/api/dialogs/__init__.py +36 -0
  171. testerkit/api/dialogs/manager.py +617 -0
  172. testerkit/api/dialogs/models.py +79 -0
  173. testerkit/api/models.py +80 -0
  174. testerkit/api/responses.py +205 -0
  175. testerkit/api/runner.py +222 -0
  176. testerkit/api/schemas.py +311 -0
  177. testerkit/benchmark/__init__.py +34 -0
  178. testerkit/benchmark/concurrency.py +248 -0
  179. testerkit/benchmark/core.py +232 -0
  180. testerkit/benchmark/runner.py +628 -0
  181. testerkit/benchmark/scenario.py +313 -0
  182. testerkit/benchmark/system.py +191 -0
  183. testerkit/benchmark/workloads.py +507 -0
  184. testerkit/catalog/__init__.py +6 -0
  185. testerkit/catalog/generic/generic_dmm.yaml +61 -0
  186. testerkit/catalog/generic/generic_eload.yaml +31 -0
  187. testerkit/catalog/generic/generic_fgen.yaml +56 -0
  188. testerkit/catalog/generic/generic_oscilloscope.yaml +45 -0
  189. testerkit/catalog/generic/generic_psu.yaml +77 -0
  190. testerkit/catalog/generic/generic_smu.yaml +73 -0
  191. testerkit/channels.py +538 -0
  192. testerkit/cli/__init__.py +32 -0
  193. testerkit/cli/_common.py +113 -0
  194. testerkit/cli/_time.py +179 -0
  195. testerkit/cli/benchmark_cmd.py +56 -0
  196. testerkit/cli/catalog_cmd.py +39 -0
  197. testerkit/cli/daemon.py +157 -0
  198. testerkit/cli/data_cmd.py +1040 -0
  199. testerkit/cli/discover_cmd.py +94 -0
  200. testerkit/cli/docs_cmd.py +100 -0
  201. testerkit/cli/instrument.py +172 -0
  202. testerkit/cli/mcp_cmd.py +37 -0
  203. testerkit/cli/metrics.py +366 -0
  204. testerkit/cli/project.py +312 -0
  205. testerkit/cli/root.py +14 -0
  206. testerkit/cli/runs.py +412 -0
  207. testerkit/cli/schema_cmd.py +87 -0
  208. testerkit/cli/serve_cmd.py +50 -0
  209. testerkit/cli/setup_cmd.py +604 -0
  210. testerkit/cli/station.py +294 -0
  211. testerkit/cli/validate.py +112 -0
  212. testerkit/client.py +463 -0
  213. testerkit/connect.py +635 -0
  214. testerkit/data/__init__.py +8 -0
  215. testerkit/data/_accumulator_pool.py +455 -0
  216. testerkit/data/_atomic.py +59 -0
  217. testerkit/data/_collection_indices.py +67 -0
  218. testerkit/data/_daemon_lifecycle.py +535 -0
  219. testerkit/data/_duckdb_daemon.py +695 -0
  220. testerkit/data/_duckdb_flight_server.py +813 -0
  221. testerkit/data/_event_filters.py +15 -0
  222. testerkit/data/_event_reader.py +101 -0
  223. testerkit/data/_flight_errors.py +199 -0
  224. testerkit/data/_flight_query.py +202 -0
  225. testerkit/data/_flight_retry.py +148 -0
  226. testerkit/data/_flight_subscribe.py +67 -0
  227. testerkit/data/_index_epoch.py +342 -0
  228. testerkit/data/_ipc_writer.py +185 -0
  229. testerkit/data/_json_safe.py +63 -0
  230. testerkit/data/_process.py +18 -0
  231. testerkit/data/_push_relay.py +124 -0
  232. testerkit/data/_runs_duckdb_daemon.py +2704 -0
  233. testerkit/data/_session_reaper.py +110 -0
  234. testerkit/data/_sql_helpers.py +30 -0
  235. testerkit/data/_store.py +24 -0
  236. testerkit/data/backends/__init__.py +7 -0
  237. testerkit/data/backends/_event_accumulator.py +957 -0
  238. testerkit/data/backends/_row_helpers.py +1172 -0
  239. testerkit/data/backends/parquet.py +1143 -0
  240. testerkit/data/backends/protocol.py +35 -0
  241. testerkit/data/channels/__init__.py +8 -0
  242. testerkit/data/channels/_flight_daemon.py +75 -0
  243. testerkit/data/channels/client.py +242 -0
  244. testerkit/data/channels/flight_manager.py +88 -0
  245. testerkit/data/channels/index.py +664 -0
  246. testerkit/data/channels/models.py +418 -0
  247. testerkit/data/channels/server.py +162 -0
  248. testerkit/data/channels/store.py +1481 -0
  249. testerkit/data/data_dir.py +61 -0
  250. testerkit/data/duckdb_manager.py +79 -0
  251. testerkit/data/event_log.py +384 -0
  252. testerkit/data/event_store.py +768 -0
  253. testerkit/data/events.py +1025 -0
  254. testerkit/data/exporters/__init__.py +6 -0
  255. testerkit/data/exporters/_helpers.py +40 -0
  256. testerkit/data/exporters/csv_exporter.py +168 -0
  257. testerkit/data/exporters/hdf5.py +234 -0
  258. testerkit/data/exporters/json_exporter.py +229 -0
  259. testerkit/data/exporters/mdf4.py +201 -0
  260. testerkit/data/exporters/stdf.py +255 -0
  261. testerkit/data/exporters/tdms.py +292 -0
  262. testerkit/data/files/__init__.py +71 -0
  263. testerkit/data/files/_backend.py +207 -0
  264. testerkit/data/files/_catalog_daemon.py +84 -0
  265. testerkit/data/files/catalog.py +218 -0
  266. testerkit/data/files/catalog_manager.py +325 -0
  267. testerkit/data/files/models.py +60 -0
  268. testerkit/data/files/serializers.py +414 -0
  269. testerkit/data/files/store.py +463 -0
  270. testerkit/data/files/streaming.py +783 -0
  271. testerkit/data/models.py +604 -0
  272. testerkit/data/ref.py +152 -0
  273. testerkit/data/retention.py +297 -0
  274. testerkit/data/run_store.py +367 -0
  275. testerkit/data/runs_duckdb_manager.py +103 -0
  276. testerkit/data/schema_dispatch.py +191 -0
  277. testerkit/data/schema_migrate.py +76 -0
  278. testerkit/data/schema_versions.py +85 -0
  279. testerkit/data/schemas.py +288 -0
  280. testerkit/data/subscribers/__init__.py +48 -0
  281. testerkit/data/subscribers/_base.py +20 -0
  282. testerkit/data/subscribers/_output_file.py +25 -0
  283. testerkit/data/subscribers/replay.py +55 -0
  284. testerkit/environment.py +84 -0
  285. testerkit/execution/__init__.py +11 -0
  286. testerkit/execution/_git.py +190 -0
  287. testerkit/execution/_state.py +740 -0
  288. testerkit/execution/accessors.py +54 -0
  289. testerkit/execution/audit.py +51 -0
  290. testerkit/execution/cascade.py +85 -0
  291. testerkit/execution/connections.py +491 -0
  292. testerkit/execution/harness.py +1931 -0
  293. testerkit/execution/instrument_events.py +42 -0
  294. testerkit/execution/limits.py +154 -0
  295. testerkit/execution/metadata.py +102 -0
  296. testerkit/execution/mocks.py +63 -0
  297. testerkit/execution/profiles.py +616 -0
  298. testerkit/execution/run_scope.py +1331 -0
  299. testerkit/execution/session_scope.py +196 -0
  300. testerkit/execution/sidecar.py +280 -0
  301. testerkit/execution/site_runner.py +705 -0
  302. testerkit/execution/sites.py +183 -0
  303. testerkit/execution/sync.py +294 -0
  304. testerkit/execution/uut_provider.py +231 -0
  305. testerkit/execution/vectors.py +205 -0
  306. testerkit/execution/verify.py +396 -0
  307. testerkit/expand.py +75 -0
  308. testerkit/files.py +235 -0
  309. testerkit/fixtures/__init__.py +6 -0
  310. testerkit/fixtures/manager.py +357 -0
  311. testerkit/grafana/__init__.py +1 -0
  312. testerkit/grafana/bootstrap.py +61 -0
  313. testerkit/grafana/cli.py +314 -0
  314. testerkit/grafana/dashboards/asset_utilization.json +92 -0
  315. testerkit/grafana/dashboards/channel_explorer.json +77 -0
  316. testerkit/grafana/dashboards/event_log.json +92 -0
  317. testerkit/grafana/dashboards/failure_pareto.json +104 -0
  318. testerkit/grafana/dashboards/measurement_distribution.json +97 -0
  319. testerkit/grafana/dashboards/measurement_trend.json +161 -0
  320. testerkit/grafana/dashboards/station_comparison.json +95 -0
  321. testerkit/grafana/dashboards/test_duration.json +104 -0
  322. testerkit/grafana/dashboards/unit_traceability.json +73 -0
  323. testerkit/grafana/dashboards/yield_overview.json +189 -0
  324. testerkit/grafana/provisioning/dashboards.yaml.j2 +12 -0
  325. testerkit/grafana/provisioning/datasources.yaml.j2 +17 -0
  326. testerkit/grafana/server.py +282 -0
  327. testerkit/init.py +724 -0
  328. testerkit/instruments/__init__.py +10 -0
  329. testerkit/instruments/base.py +82 -0
  330. testerkit/instruments/discovery/__init__.py +62 -0
  331. testerkit/instruments/discovery/_base.py +174 -0
  332. testerkit/instruments/discovery/lxi.py +152 -0
  333. testerkit/instruments/discovery/ni.py +95 -0
  334. testerkit/instruments/discovery/serial.py +73 -0
  335. testerkit/instruments/discovery/visa.py +98 -0
  336. testerkit/instruments/lifecycle.py +213 -0
  337. testerkit/instruments/loader.py +79 -0
  338. testerkit/instruments/locks.py +178 -0
  339. testerkit/instruments/mocks.py +230 -0
  340. testerkit/instruments/observer.py +270 -0
  341. testerkit/instruments/observers/__init__.py +36 -0
  342. testerkit/instruments/observers/_base.py +68 -0
  343. testerkit/instruments/observers/daqmx.py +70 -0
  344. testerkit/instruments/observers/descriptor.py +69 -0
  345. testerkit/instruments/observers/generic.py +92 -0
  346. testerkit/instruments/observers/lantz.py +31 -0
  347. testerkit/instruments/observers/modbus.py +96 -0
  348. testerkit/instruments/observers/motion.py +68 -0
  349. testerkit/instruments/observers/ni_modular.py +73 -0
  350. testerkit/instruments/observers/ophyd.py +80 -0
  351. testerkit/instruments/observers/pymeasure.py +120 -0
  352. testerkit/instruments/observers/qcodes.py +66 -0
  353. testerkit/instruments/observers/scpi.py +88 -0
  354. testerkit/instruments/observers/tektronix.py +57 -0
  355. testerkit/instruments/observers/visa.py +103 -0
  356. testerkit/instruments/pool.py +459 -0
  357. testerkit/instruments/proxy.py +59 -0
  358. testerkit/instruments/route_manager.py +329 -0
  359. testerkit/instruments/routed_proxy.py +88 -0
  360. testerkit/instruments/server.py +508 -0
  361. testerkit/instruments/switch.py +43 -0
  362. testerkit/instruments/visa.py +294 -0
  363. testerkit/matching/__init__.py +6 -0
  364. testerkit/matching/service.py +969 -0
  365. testerkit/mcp/__init__.py +6 -0
  366. testerkit/mcp/server.py +681 -0
  367. testerkit/mcp/tools.py +1868 -0
  368. testerkit/models/__init__.py +18 -0
  369. testerkit/models/capability.py +598 -0
  370. testerkit/models/catalog.py +76 -0
  371. testerkit/models/data_options.py +153 -0
  372. testerkit/models/enums.py +334 -0
  373. testerkit/models/instrument.py +152 -0
  374. testerkit/models/instrument_asset.py +25 -0
  375. testerkit/models/part.py +271 -0
  376. testerkit/models/part_manifest.py +96 -0
  377. testerkit/models/project.py +114 -0
  378. testerkit/models/station.py +140 -0
  379. testerkit/models/test_config.py +748 -0
  380. testerkit/ontology/__init__.py +39 -0
  381. testerkit/ontology/schema.py +188 -0
  382. testerkit/ontology/testerkit.yaml +1420 -0
  383. testerkit/parts/__init__.py +8 -0
  384. testerkit/parts/context.py +181 -0
  385. testerkit/parts/folder.py +251 -0
  386. testerkit/parts/loader.py +27 -0
  387. testerkit/prompts/__init__.py +17 -0
  388. testerkit/prompts/core.py +133 -0
  389. testerkit/pytest_plugin/__init__.py +1287 -0
  390. testerkit/pytest_plugin/autouse.py +369 -0
  391. testerkit/pytest_plugin/helpers.py +354 -0
  392. testerkit/pytest_plugin/hooks.py +1982 -0
  393. testerkit/pytest_plugin/markers.py +203 -0
  394. testerkit/pytest_plugin/retry.py +37 -0
  395. testerkit/pytest_plugin/sweeps.py +117 -0
  396. testerkit/queries.py +78 -0
  397. testerkit/reports/__init__.py +6 -0
  398. testerkit/reports/core.py +492 -0
  399. testerkit/reports/datasheet.py +831 -0
  400. testerkit/reports/templates/datasheet.html +383 -0
  401. testerkit/reports/templates/default.html +153 -0
  402. testerkit/sbom.py +142 -0
  403. testerkit/schema_export.py +101 -0
  404. testerkit/signals.py +63 -0
  405. testerkit/skills/README.md +58 -0
  406. testerkit/skills/templates/project-instructions.md +125 -0
  407. testerkit/skills/testerkit-analysis/SKILL.md +87 -0
  408. testerkit/skills/testerkit-capture/SKILL.md +114 -0
  409. testerkit/skills/testerkit-data/SKILL.md +138 -0
  410. testerkit/skills/testerkit-datasheets/SKILL.md +100 -0
  411. testerkit/skills/testerkit-datasheets/agents/scaffold-writer.md +115 -0
  412. testerkit/skills/testerkit-datasheets/agents/section-extractor.md +98 -0
  413. testerkit/skills/testerkit-datasheets/agents/section-reviewer.md +153 -0
  414. testerkit/skills/testerkit-datasheets/agents/section-splitter.md +89 -0
  415. testerkit/skills/testerkit-datasheets/agents/section-writer.md +226 -0
  416. testerkit/skills/testerkit-datasheets/references/catalog-pipeline.md +271 -0
  417. testerkit/skills/testerkit-datasheets/references/process-queue.md +42 -0
  418. testerkit/skills/testerkit-datasheets/references/scaffold.md +156 -0
  419. testerkit/skills/testerkit-datasheets/references/test-pipeline.md +312 -0
  420. testerkit/skills/testerkit-debug/SKILL.md +127 -0
  421. testerkit/skills/testerkit-interactive/SKILL.md +188 -0
  422. testerkit/skills/testerkit-interactive/references/live-ui-patterns.md +102 -0
  423. testerkit/skills/testerkit-mocks/SKILL.md +128 -0
  424. testerkit/skills/testerkit-parts/SKILL.md +126 -0
  425. testerkit/skills/testerkit-profiles/SKILL.md +139 -0
  426. testerkit/skills/testerkit-sites/SKILL.md +140 -0
  427. testerkit/skills/testerkit-stations/SKILL.md +146 -0
  428. testerkit/skills/testerkit-tests/SKILL.md +136 -0
  429. testerkit/store.py +1639 -0
  430. testerkit/ui/__init__.py +71 -0
  431. testerkit/ui/_asgi.py +162 -0
  432. testerkit/ui/app.py +32 -0
  433. testerkit/ui/components/__init__.py +13 -0
  434. testerkit/ui/components/artifact_viewer.py +250 -0
  435. testerkit/ui/components/channel_values.py +159 -0
  436. testerkit/ui/components/event_timeline.py +222 -0
  437. testerkit/ui/components/execution_gantt.py +210 -0
  438. testerkit/ui/components/file_streams.py +147 -0
  439. testerkit/ui/components/instrument_activity.py +146 -0
  440. testerkit/ui/components/session_table.py +118 -0
  441. testerkit/ui/pages/__init__.py +25 -0
  442. testerkit/ui/pages/channels/__init__.py +4 -0
  443. testerkit/ui/pages/channels/detail.py +932 -0
  444. testerkit/ui/pages/channels/list.py +515 -0
  445. testerkit/ui/pages/dashboard.py +236 -0
  446. testerkit/ui/pages/designer/__init__.py +5 -0
  447. testerkit/ui/pages/designer/graph.py +635 -0
  448. testerkit/ui/pages/designer/matching.py +663 -0
  449. testerkit/ui/pages/designer/page.py +593 -0
  450. testerkit/ui/pages/designer/properties.py +591 -0
  451. testerkit/ui/pages/designer/state.py +468 -0
  452. testerkit/ui/pages/docs/__init__.py +6 -0
  453. testerkit/ui/pages/docs/index.py +95 -0
  454. testerkit/ui/pages/docs/page.py +698 -0
  455. testerkit/ui/pages/events/__init__.py +3 -0
  456. testerkit/ui/pages/events/list.py +263 -0
  457. testerkit/ui/pages/explore.py +1108 -0
  458. testerkit/ui/pages/files/__init__.py +4 -0
  459. testerkit/ui/pages/files/detail.py +426 -0
  460. testerkit/ui/pages/files/list.py +447 -0
  461. testerkit/ui/pages/fixtures/__init__.py +8 -0
  462. testerkit/ui/pages/fixtures/detail.py +280 -0
  463. testerkit/ui/pages/fixtures/edit.py +370 -0
  464. testerkit/ui/pages/fixtures/list.py +180 -0
  465. testerkit/ui/pages/fixtures/new.py +195 -0
  466. testerkit/ui/pages/instruments/__init__.py +4 -0
  467. testerkit/ui/pages/instruments/detail.py +320 -0
  468. testerkit/ui/pages/instruments/edit.py +482 -0
  469. testerkit/ui/pages/instruments/list.py +249 -0
  470. testerkit/ui/pages/instruments/new.py +200 -0
  471. testerkit/ui/pages/launch.py +261 -0
  472. testerkit/ui/pages/live.py +124 -0
  473. testerkit/ui/pages/metrics_page.py +1229 -0
  474. testerkit/ui/pages/parts/__init__.py +11 -0
  475. testerkit/ui/pages/parts/detail.py +202 -0
  476. testerkit/ui/pages/parts/edit.py +310 -0
  477. testerkit/ui/pages/parts/list.py +160 -0
  478. testerkit/ui/pages/parts/new.py +170 -0
  479. testerkit/ui/pages/parts/requirements.py +153 -0
  480. testerkit/ui/pages/parts/stations.py +199 -0
  481. testerkit/ui/pages/profiles/__init__.py +4 -0
  482. testerkit/ui/pages/profiles/detail.py +113 -0
  483. testerkit/ui/pages/profiles/list.py +86 -0
  484. testerkit/ui/pages/results/__init__.py +4 -0
  485. testerkit/ui/pages/results/detail.py +631 -0
  486. testerkit/ui/pages/results/list.py +230 -0
  487. testerkit/ui/pages/stations/__init__.py +4 -0
  488. testerkit/ui/pages/stations/detail.py +256 -0
  489. testerkit/ui/pages/stations/edit.py +273 -0
  490. testerkit/ui/pages/stations/list.py +180 -0
  491. testerkit/ui/pages/stations/new.py +311 -0
  492. testerkit/ui/pages/tests/__init__.py +4 -0
  493. testerkit/ui/pages/tests/detail.py +152 -0
  494. testerkit/ui/pages/tests/list.py +194 -0
  495. testerkit/ui/pages/uuts/__init__.py +4 -0
  496. testerkit/ui/pages/uuts/list.py +97 -0
  497. testerkit/ui/shared/__init__.py +8 -0
  498. testerkit/ui/shared/components.py +1826 -0
  499. testerkit/ui/shared/dialogs.py +105 -0
  500. testerkit/ui/shared/event_binding.py +194 -0
  501. testerkit/ui/shared/layout.py +314 -0
  502. testerkit/ui/shared/services.py +1719 -0
  503. testerkit/ui/shared/timestamps.py +21 -0
  504. testerkit/ui/static/branding/favicon-16.png +0 -0
  505. testerkit/ui/static/branding/favicon-32.png +0 -0
  506. testerkit/ui/static/branding/favicon-48.png +0 -0
  507. testerkit/ui/static/branding/testerkit-icon-256.png +0 -0
  508. testerkit/ui/static/branding/testerkit-mark.svg +1 -0
  509. testerkit/ui/static/branding/testerkit-wordmark.svg +1 -0
  510. testerkit/ui/static/global.css +465 -0
  511. testerkit/utils/__init__.py +17 -0
  512. testerkit/utils/enum_meta.py +800 -0
  513. testerkit/utils/paths.py +75 -0
  514. testerkit/utils/ranges.py +257 -0
  515. testerkit/validation.py +82 -0
  516. testerkit/verbs.py +142 -0
  517. testerkit-0.4.0.dist-info/METADATA +250 -0
  518. testerkit-0.4.0.dist-info/RECORD +521 -0
  519. testerkit-0.4.0.dist-info/WHEEL +4 -0
  520. testerkit-0.4.0.dist-info/entry_points.txt +5 -0
  521. testerkit-0.4.0.dist-info/licenses/LICENSE +191 -0
@@ -0,0 +1,138 @@
1
+ ---
2
+ name: testerkit-data
3
+ description: Use when a user wants to read, query, or export existing TesterKit test data — runs, steps, measurements, channels, files, or events — or understand the data stores and how to access them (models, CLI, Query API, MCP). Not computing a statistic across runs (that's testerkit-analysis) and not diagnosing why one run failed (that's testerkit-debug).
4
+ ---
5
+
6
+ # Reading TesterKit data
7
+
8
+ The data already exists on disk. This skill covers the **stores, the model,
9
+ and every read surface** — models, CLI, Query API, MCP, UI — so a question
10
+ turns into the right access call.
11
+
12
+ ## The one rule
13
+
14
+ **Never read `data/**/*.parquet` or `data/*/_index.*.duckdb` directly.** That
15
+ layout is internal and content-addressed — the fingerprint in an index
16
+ filename is a hash of the current schema, so it renames on any version bump and
17
+ a hand-rolled reader breaks silently on upgrade. Every question below has a
18
+ stable, purpose-built surface. If none exposes the shape you need, extend the
19
+ Query API — don't reach into the files.
20
+
21
+ ## 1. The stores
22
+
23
+ TesterKit keeps four data stores under the project `data/` dir. All are derived
24
+ from the event log:
25
+
26
+ | Store | Holds | Read via |
27
+ |---|---|---|
28
+ | runs / measurements | tabular run → step → measurement records | CLI (`testerkit runs`/`show`), Query API, `testerkit_runs`/`testerkit_steps` |
29
+ | channels | streaming / waveform samples | `testerkit.channels` module, `testerkit_channels`, UI |
30
+ | files | blobs & growing artifacts (photos, logs, vendor captures) | `testerkit.files` module, `testerkit_files`, UI |
31
+ | events | the append-only log every store is derived from | `testerkit_events` / `testerkit_sessions`, UI |
32
+
33
+ Tabular runs data has a first-class **CLI**; channels, files, and events read
34
+ through the UI, MCP, HTTP, or the Python modules — there is no `testerkit
35
+ channels`/`files`/`events` subcommand.
36
+
37
+ ## 2. The model
38
+
39
+ A run carries its step tree; each step carries three role-tagged
40
+ `list<struct>` lanes — `inputs`, `outputs`, `measurements`. Reference a value
41
+ by **role + name**:
42
+
43
+ ```python
44
+ from testerkit.queries import FieldRef
45
+ FieldRef.measurement("v_rail") # a judged measurement (has a limit)
46
+ FieldRef.output("capture_length") # a recorded output reading
47
+ FieldRef.input("vin") # a stimulus input
48
+ ```
49
+
50
+ Only `measurements` carry limits; `inputs`/`outputs` are record-only. Full
51
+ shape: `reference/data/models` and `reference/data/parquet-schema`.
52
+
53
+ ## 3. CLI (tabular data)
54
+
55
+ ```bash
56
+ testerkit runs --station bench_01 --since 7d --json # list / filter runs
57
+ testerkit show <run_id> # one run: outcome, steps, measurements
58
+ testerkit show <run_id> -f json # machine-readable (also html|pdf|csv)
59
+ testerkit show <run_id> --env # captured environment snapshot
60
+ testerkit export <run_id> -f stdf -o exports/ # STDF and other event-shaped formats
61
+ testerkit sbom <run_id> -o sbom.json # CycloneDX 1.6
62
+ ```
63
+
64
+ `show`/`export`'s id is a run_id or session_id prefix, auto-detected. Prefer
65
+ `--json` for tool use — stable across schema changes and token-efficient.
66
+ `testerkit show` prints measurements only; it doesn't list outputs or artifact URIs.
67
+
68
+ ## 4. Query API (scripted)
69
+
70
+ ```python
71
+ from testerkit.queries import RunsQuery, StepsQuery, MeasurementsQuery, FieldRef
72
+
73
+ with RunsQuery() as q:
74
+ for r in q.list_recent(limit=20, outcome="failed"):
75
+ print(r.uut_serial_number, r.station_hostname, r.outcome)
76
+ q.get(run_id) # one run
77
+ q.list_for_session(session_id)
78
+
79
+ with StepsQuery() as s:
80
+ s.list_for_run(run_id) # flat step list
81
+ s.tree_for_run(run_id) # nested step tree
82
+
83
+ with MeasurementsQuery() as m:
84
+ m.parametric(y=FieldRef.measurement("v_rail"), x=FieldRef.input("vin"))
85
+ m.histogram(field=FieldRef.output("capture_length"))
86
+ ```
87
+
88
+ Opening a query class with no args reads the active project's data dir; always
89
+ close it (or use `with`). These are the same classes `testerkit serve` renders, so
90
+ anything scriptable here is clickable there. Computing yield/Ppk/Pareto/trend
91
+ over these rows is `testerkit-analysis`.
92
+
93
+ ## 5. Channels & files readback
94
+
95
+ | Data | Surface |
96
+ |---|---|
97
+ | Channel, one-shot pull | `testerkit.channels.query(name, last_n=..., max_points=...)` |
98
+ | Channel, live gauge/chart | `testerkit.channels.latest(name, cb)` / `.live(name, cb, max_hz=...)` |
99
+ | Channel, agent/remote | MCP `testerkit_channels(channel_id, session_id=, last_n=, max_points=)` |
100
+ | Channel, human | `testerkit serve` → `/channels/<channel_id>` |
101
+ | Artifact catalog (metadata, not bytes) | MCP `testerkit_files(uri=, session_id=, run_id=)` |
102
+ | Artifact, human | `testerkit serve` → `/files` |
103
+
104
+ Filter artifact readback by `session_id`, not `run_id`, to catch every artifact
105
+ from a run — `observe`-routed blobs carry no `run_id`. Writing channels/files in
106
+ the first place is `testerkit-capture`.
107
+
108
+ ## 6. Events
109
+
110
+ The event log is the source every other store derives from — read it for the
111
+ raw ordered stream, or when a projection looks wrong:
112
+
113
+ ```
114
+ MCP testerkit_events(session_id=, event_type=, role=, since=, limit=)
115
+ MCP testerkit_sessions(project=) # session index
116
+ ```
117
+
118
+ ## 7. MCP read tools
119
+
120
+ | MCP tool | Mirrors |
121
+ |---|---|
122
+ | `testerkit_runs(action="list"\|"get", run_id=...)` | `testerkit runs` / `RunsQuery` |
123
+ | `testerkit_steps(run_id=..., action="list"\|"tree")` | `StepsQuery.list_for_run` / `.tree_for_run` |
124
+ | `testerkit_channels` / `testerkit_files` / `testerkit_events` / `testerkit_sessions` | channel / file / event / session reads |
125
+
126
+ ## Deeper
127
+ Read the docs:
128
+ ```bash
129
+ testerkit docs show concepts/data/data-stores
130
+ testerkit docs show reference/data/models
131
+ testerkit docs show reference/data/query-api
132
+ testerkit docs show reference/data/parquet-schema
133
+ testerkit docs show how-to/data/mcp-query-runs
134
+ testerkit docs show how-to/data/export-results
135
+ ```
136
+ Sibling skills: `testerkit-analysis` (compute a statistic over these records),
137
+ `testerkit-capture` (write channels/files in the first place), `testerkit-debug`
138
+ (why one run failed).
@@ -0,0 +1,100 @@
1
+ ---
2
+ name: testerkit-datasheets
3
+ description: Use ONLY when the user has an instrument or part datasheet PDF to import into TesterKit config (an instrument → catalog entry, or a part → part spec). For writing tests without a datasheet, use testerkit-tests instead.
4
+ ---
5
+
6
+ # Datasheet import
7
+
8
+ Turn a datasheet PDF into TesterKit config: an **instrument** datasheet becomes a
9
+ catalog entry, a **part/DUT** datasheet becomes a part spec plus a test. This is
10
+ a deliberate, gated, multi-phase procedure — run it because the user asked to
11
+ import a datasheet, never as a reflex to "write me a test." If there's no PDF in
12
+ hand, you're in the wrong skill (see `testerkit-tests`).
13
+
14
+ ## 1. Route: what did they hand you?
15
+
16
+ | The user has… | Pipeline | Reference |
17
+ |---|---|---|
18
+ | An **instrument** datasheet PDF (DMM, PSU, scope, load…) — need exact specs, channels, accuracy | catalog pipeline | `references/catalog-pipeline.md` |
19
+ | A **part/DUT** datasheet PDF — need characteristics, pins, and a test that exercises them | test pipeline | `references/test-pipeline.md` |
20
+ | A **well-known instrument, no PDF** (Keysight, Tektronix, Rigol, Fluke…) — fast approximate entry | scaffold | `references/scaffold.md` |
21
+ | A **batch** of pending PDFs already queued in `catalog/QUEUE.md` | queue processor | `references/process-queue.md` |
22
+
23
+ If the user's ask doesn't fit any row — e.g. they want a test but have no
24
+ datasheet at all — hand off to `testerkit-tests` instead of forcing a pipeline here.
25
+
26
+ ## 2. Instrument datasheet → catalog entry
27
+
28
+ Read `references/catalog-pipeline.md` and follow it exactly, phase by phase. Do
29
+ not summarize or shortcut the phases here — that file is the orchestration
30
+ contract, not this one.
31
+
32
+ In outline: the orchestrator never reads the PDF itself. It spawns five
33
+ sub-agents from `agents/` in sequence — `section-splitter` maps the PDF into
34
+ sections, `scaffold-writer` writes the device-level YAML (channels, connectors,
35
+ board attributes), then per section `section-extractor` → `section-writer` →
36
+ `section-reviewer` cycle until a mechanical audit script and the reviewer both
37
+ report clean. Every phase ends in a checkpoint or gate tag; do not proceed past
38
+ one that hasn't fired.
39
+
40
+ The output is a catalog YAML entry — the same shape a station's
41
+ `catalog_ref:` resolves against (see `testerkit-stations`).
42
+
43
+ ## 3. Part/DUT datasheet → part spec + test
44
+
45
+ Read `references/test-pipeline.md` and follow it exactly, phase by phase. This
46
+ pipeline is collaborative — it gates on user approval at every phase (part spec,
47
+ instrument recommendation, station config, generated test) via
48
+ `ask_user_input_v0` / `AskUserQuestion`. Never assume approval and skip a gate.
49
+
50
+ In outline: parse the datasheet into characteristics + pins → save a part spec
51
+ via `testerkit_project(action="save", type="part", ...)` → recommend catalog
52
+ instruments via `testerkit_match` (falling back to generic instruments or the
53
+ scaffold path below if the catalog has no match) → build a station → generate
54
+ the test file plus its sidecar YAML. Characteristic and limit shapes match what
55
+ `testerkit-parts` and `testerkit-tests` describe — this pipeline is how those artifacts
56
+ get their first draft from a datasheet instead of from scratch.
57
+
58
+ ## 4. No PDF, well-known instrument → scaffold
59
+
60
+ If the user names a common instrument by model number and doesn't have (or need)
61
+ the datasheet, read `references/scaffold.md` and follow it. It writes a catalog
62
+ entry from model knowledge, marks it `scaffold: true`, and uses conservative
63
+ ranges — never claim accuracy you can't back with a source. This is the fast
64
+ path; the catalog pipeline in step 2 is the thorough path when exact
65
+ specifications matter. If confidence in the instrument is low, say so and
66
+ recommend the catalog pipeline instead of guessing.
67
+
68
+ ## 5. Batch of queued datasheets
69
+
70
+ If the user asks to work through a backlog — "process the queue," "do all the
71
+ pending datasheets" — read `references/process-queue.md` and follow it. It loops
72
+ the catalog pipeline (step 2) over every `pending` / `pending:redo` row in
73
+ `catalog/QUEUE.md`, updating each row's status as it completes, and does not stop
74
+ to ask the user between instruments.
75
+
76
+ ## 6. Validate before declaring done
77
+
78
+ Every pipeline above ends with the artifact still unverified until you run:
79
+
80
+ ```bash
81
+ testerkit validate --type catalog <path>.yaml # instrument pipeline
82
+ testerkit validate --type part <path>.yaml # test pipeline part spec
83
+ testerkit validate --type station <path>.yaml # test pipeline station config
84
+ ```
85
+
86
+ or, for the test pipeline, the equivalent MCP save calls
87
+ (`testerkit_project(action="save", type=..., ...)`), which validate server-side
88
+ against the same Pydantic models. A pipeline is not complete until its YAML
89
+ validates clean — do not report success on an artifact you haven't checked.
90
+
91
+ ## Deeper
92
+
93
+ `references/`: `catalog-pipeline.md` (instrument → catalog, full phase spec),
94
+ `test-pipeline.md` (part → spec/station/test, full phase spec), `scaffold.md`
95
+ (no-PDF fast path), `process-queue.md` (batch driver). `agents/`: the five
96
+ sub-agent prompts the catalog pipeline spawns
97
+ (`section-splitter`, `scaffold-writer`, `section-extractor`, `section-writer`,
98
+ `section-reviewer`). Sibling skills: `testerkit-tests` (writing tests without a
99
+ datasheet), `testerkit-stations` (what a catalog entry feeds into), `testerkit-parts`
100
+ (part characteristics and limits once the spec exists).
@@ -0,0 +1,115 @@
1
+ ---
2
+ name: scaffold-writer
3
+ description: Reads targeted pages of a datasheet PDF and writes the device-level catalog YAML (catalog_entry with channels, interfaces, board attributes). Does NOT extract capabilities.
4
+ variables: PDF_PATH, YAML_PATH, INSTRUMENT_ID, OVERVIEW_PAGES, CONNECTOR_PAGES, GENERAL_PAGES, ENUM_CONNECTORS, ENUM_TERMINALS, ENUM_GROUNDS
5
+ ---
6
+
7
+ **Recommended model tier:** high-capability reasoning (Anthropic Opus, Google Gemini 2.5 Pro, OpenAI GPT-5 / o-series, or equivalent). Targeted PDF reading + accurate structural extraction needs the strongest reasoning model your client offers; mid-tier models miss connector enumerations and board-attribute detail. If your client supports per-subagent model selection (Claude Code via `model:` frontmatter, for example), set it explicitly to a high-tier model.
8
+
9
+ # Scaffold Writer Agent
10
+
11
+ You read targeted pages of an instrument datasheet and write the device-level catalog YAML. That is your ONLY job. You do NOT extract capabilities or spec tables. You write the catalog_entry shell that capability agents will populate later.
12
+
13
+ **Do NOT read other catalog YAML files as examples.** Your only inputs are the PDF pages and the schema/enum references below. Reading other YAML files risks copying incorrect patterns or values from different instruments.
14
+
15
+ **Tool rules:**
16
+ - Use Read tool to read files, Write/Edit tools to create/modify files. NEVER use Bash cat, heredocs, or echo for file I/O.
17
+ - Write YAML directly via Write/Edit. NEVER create Python scripts to generate YAML.
18
+
19
+ ## Your Assignment
20
+
21
+ - **PDF:** `{{PDF_PATH}}`
22
+ - **Output YAML:** `{{YAML_PATH}}`
23
+ - **Instrument ID:** `{{INSTRUMENT_ID}}`
24
+ - **Overview pages:** {{OVERVIEW_PAGES}}
25
+ - **Connector pages:** {{CONNECTOR_PAGES}}
26
+ - **General spec pages:** {{GENERAL_PAGES}}
27
+
28
+ ## Instructions
29
+
30
+ ### Step 1: Read the targeted pages
31
+
32
+ Read ONLY the pages listed above (overview, connector, general spec pages). Read them carefully — you have few pages to cover, so be thorough.
33
+
34
+ From the overview pages, extract:
35
+ - Manufacturer name
36
+ - Model number and variants
37
+ - Part description (1-2 sentences)
38
+
39
+ From the connector/I/O pages, extract:
40
+ - Every physical connector: name, type, terminal configuration, ground topology
41
+ - Front panel vs rear panel layout
42
+ - Optional connectors (e.g., "Option 1EM adds rear RF output")
43
+
44
+ From the general spec pages, extract:
45
+ - Operating temperature range
46
+ - Storage temperature range
47
+ - Weight
48
+ - Power requirements (voltage, frequency, power consumption)
49
+ - Warmup time
50
+ - Calibration interval
51
+ - Max working voltage
52
+ - Pollution degree, max altitude, humidity
53
+ - Any other board-level specs
54
+
55
+ ### Step 2: Read schema references
56
+
57
+ Use these enum values — they are the ONLY valid values for channel fields:
58
+
59
+ **ConnectorType:** {{ENUM_CONNECTORS}}
60
+
61
+ **TerminalRole:** {{ENUM_TERMINALS}}
62
+
63
+ **GroundTopology:** {{ENUM_GROUNDS}}
64
+
65
+ Read `docs/reference/catalog/schema.md` for attribute format (scalar `value` or min/max `range`).
66
+
67
+ ### Step 3: Write the scaffold YAML
68
+
69
+ Write the initial YAML to `{{YAML_PATH}}`:
70
+
71
+ 1. **3-line header comment:** instrument name, PDF source, key summary
72
+ 2. **catalog_entry:**
73
+ - manufacturer, model, description
74
+ - interfaces (e.g., pxi, usb, lan, gpib)
75
+ - channels — every physical connector with documented electrical specs
76
+ - attributes — board-level facts (operating temp, weight, power, warmup, cal interval, etc.)
77
+ - capabilities: [] (empty — section agents will populate this)
78
+
79
+ **Channel rules:**
80
+ - Include ALL channels from the PDF — every physical connector with documented electrical specs
81
+ - Include optional channels with a note about which option adds them
82
+ - Use compact range syntax: `"ai[0:7]"` not arrays of individual names
83
+ - Set correct `terminals`, `connector`, and `ground` from the PDF
84
+ - Use MeasurementFunction enum values for naming guidance
85
+
86
+ **Board-level attribute format:**
87
+ - Scalar: `warmup_time: {value: 30, unit: min}`
88
+ - Range: `operating_temperature: {range: {min: 0, max: 55, unit: degC}}`
89
+
90
+ ### Step 4: Validate the scaffold loads
91
+
92
+ Run:
93
+ ```
94
+ uv run testerkit validate --type catalog {{YAML_PATH}}
95
+ ```
96
+
97
+ Fix any errors until it loads clean.
98
+
99
+ ### Step 5: Return your results
100
+
101
+ Return this exact format:
102
+
103
+ ```
104
+ SCAFFOLD RESULT
105
+ ===============
106
+ Written to: {{YAML_PATH}}
107
+ Channels: <list with connectors>
108
+ Interfaces: <list>
109
+ Board attributes: <count>
110
+ Status: validated clean / errors
111
+
112
+ CHANNELS YAML
113
+ =============
114
+ <just the channels: dict from the scaffold, for injection into downstream prompts>
115
+ ```
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: section-extractor
3
+ description: Reads PDF pages and produces a complete structured inventory file. ONE job — extraction only, no YAML, no schema knowledge.
4
+ variables: PDF_PATH, PAGES, SECTION_NAME, INVENTORY_PATH
5
+ ---
6
+
7
+ **Recommended model tier:** high-capability reasoning (Anthropic Opus, Google Gemini 2.5 Pro, OpenAI GPT-5 / o-series, or equivalent). Complete-and-mechanical PDF extraction is the most demanding step in the workflow; a weaker model drops rows, misreads accuracy tables, and produces inventories that downstream agents can't recover from. If your client supports per-subagent model selection (Claude Code via `model:` frontmatter, for example), set it explicitly to a high-tier model.
8
+
9
+ # Section Extractor Agent
10
+
11
+ You read specific pages of an instrument datasheet PDF and produce a complete structured inventory file. That is your ONLY job. You do NOT write YAML. You do NOT know the catalog schema. You extract what the PDF says, completely and mechanically.
12
+
13
+ **Tool rules:**
14
+ - Use Read tool to read files, Write tool to create files. NEVER use Bash cat, heredocs, or echo for file I/O.
15
+
16
+ ## Your Assignment
17
+
18
+ - **PDF:** `{{PDF_PATH}}`
19
+ - **Pages to read:** {{PAGES}}
20
+ - **Section:** {{SECTION_NAME}}
21
+ - **Output:** `{{INVENTORY_PATH}}`
22
+
23
+ ## Instructions
24
+
25
+ <step id="1" name="Read PDF pages">
26
+ Read your assigned PDF pages (2-4 pages at a time). For EVERY table on every page:
27
+ - List ALL column headers. Capture EVERY column, not just Standard/default. Option columns (e.g., EP3, EP4, Option 001) are just as important as the base column.
28
+ - Count rows and columns.
29
+ - Note the table title/caption.
30
+
31
+ Also identify: non-table specs (bullets, prose, diagram labels), footnotes, user-selectable settings, and **qualifier indicators** (look for "typical", "nominal", "supplemental", "guaranteed", "warranted", "specification" in table headers, footnotes, or row annotations).
32
+ </step>
33
+
34
+ <step id="2" name="Write inventory">
35
+ Write the inventory to `{{INVENTORY_PATH}}` using this exact format:
36
+
37
+ ```
38
+ SECTION INVENTORY
39
+ =================
40
+ Section: {{SECTION_NAME}}
41
+ Pages: {{PAGES}}
42
+ Tables found: <N>
43
+ Total spec rows: <N>
44
+ Footnotes: <N>
45
+
46
+ TABLE 1: <title>
47
+ Caption conditions: <conditions in title>
48
+ Column headers: <col1> | <col2> | ...
49
+ | # | <col1> | <col2> | ... | Footnotes |
50
+ |---|--------|--------|-----|-----------|
51
+ | 1 | ... | ... | ... | 1,2 |
52
+
53
+ For row-spanning group headers:
54
+ GROUP: <Range: 100mV>
55
+ | 1 | 1-40 Hz | ±0.1% | ±0.02% | |
56
+
57
+ TABLE 2: <title>
58
+ ...
59
+
60
+ NON-TABLE SPECS:
61
+ | # | Source | Parameter | Value | Units | Conditions |
62
+ |---|--------|-----------|-------|-------|------------|
63
+
64
+ FOOTNOTES:
65
+ | # | Ref | Text | Referenced by |
66
+ |---|-----|------|---------------|
67
+
68
+ USER-SELECTABLE SETTINGS:
69
+ | # | Setting | Options or Range | Applies to |
70
+ |---|---------|-----------------|------------|
71
+ ```
72
+ </step>
73
+
74
+ <step id="3" name="Self-check">
75
+ Re-read EACH page of your assignment. Count the tables visible on each page. Compare to your inventory.
76
+
77
+ For each page, verify:
78
+ - Every table on this page appears in the inventory
79
+ - Every column of every table is captured (not just the first few)
80
+ - Row counts match
81
+
82
+ If you find anything missing, update the inventory file before proceeding.
83
+ </step>
84
+
85
+ <step id="4" name="Return">
86
+ Return this exact format:
87
+
88
+ ```
89
+ EXTRACTION RESULT
90
+ =================
91
+ Tables found: N
92
+ Table 1: "<title>" — R rows x C columns
93
+ Table 2: "<title>" — R rows x C columns
94
+ Total spec rows: N
95
+ Footnotes: N
96
+ Inventory: {{INVENTORY_PATH}}
97
+ ```
98
+ </step>
@@ -0,0 +1,153 @@
1
+ ---
2
+ name: section-reviewer
3
+ description: Reviews AND fixes catalog YAML against an inventory file. Semantic checks only — no PDF access. Complements the mechanical audit script.
4
+ variables: YAML_PATH, SECTION_NAME, INVENTORY_PATH, CAPABILITIES, ENUM_LIST
5
+ ---
6
+
7
+ **Recommended model tier:** high-capability reasoning (Anthropic Opus, Google Gemini 2.5 Pro, OpenAI GPT-5 / o-series, or equivalent). Semantic catalog review requires cross-referencing the inventory against the produced YAML and spotting subtle mapping errors that mechanical audits miss; this is judgment work where a weaker model lets bugs through. If your client supports per-subagent model selection (Claude Code via `model:` frontmatter, for example), set it explicitly to a high-tier model.
8
+
9
+ # Section Reviewer-Fixer Agent
10
+
11
+ You review catalog YAML against a structured inventory file, then FIX any issues you find directly in the YAML. You do NOT read the PDF — the inventory is your source of truth.
12
+
13
+ **Tool rules:**
14
+ - Use Read tool to read files, Edit tool to modify files. NEVER use Bash cat, heredocs, or echo for file I/O.
15
+ - NEVER create Python scripts to generate or fix YAML. Make edits directly.
16
+
17
+ The mechanical audit script runs after you and handles: name-encoded attributes, comments with specs, channel refs, when-value types, Pydantic validation, vacuous SpecBands, duplicate names. You handle ONLY the semantic checks below.
18
+
19
+ ## Your Assignment
20
+
21
+ - **YAML:** `{{YAML_PATH}}`
22
+ - **Section:** {{SECTION_NAME}}
23
+ - **Inventory:** `{{INVENTORY_PATH}}`
24
+ - **Capabilities to check:** {{CAPABILITIES}}
25
+
26
+ <rules>
27
+ - **ACTIONABLE ONLY.** Only flag issues where you can make a specific YAML edit. No awareness flags, design opinions, or suggestions.
28
+ - **THOROUGH.** Check every inventory row, every capability, every control. Do not leave things for later rounds.
29
+ - **IN-SCOPE ONLY.** Only check capabilities listed in {{CAPABILITIES}}.
30
+ - **FIX SURGICALLY.** When you find an issue, edit ONLY the affected lines. Do NOT restructure, rename, or refactor anything beyond the specific fix.
31
+ - **VALIDATE AFTER FIXES.** Run `uv run testerkit validate --type catalog {{YAML_PATH}}` after any edits.
32
+ </rules>
33
+
34
+ ## Instructions
35
+
36
+ <step id="1">
37
+ Read the inventory file at `{{INVENTORY_PATH}}`. Read the YAML file at `{{YAML_PATH}}`.
38
+ Only review capabilities whose function is in {{CAPABILITIES}}.
39
+ </step>
40
+
41
+ <step id="2" name="Row-by-Row Trace">
42
+ Before running checks, build a TRACE TABLE. For EVERY inventory table row, write one line:
43
+
44
+ ```
45
+ ROW TRACE
46
+ =========
47
+ | Inventory Row | YAML Location | Verdict |
48
+ |---|---|---|
49
+ | Frequency option 506: 9 kHz – 6 GHz | rf_cw.signals.frequency.specs[0] | OK |
50
+ | Aging rate first year: 0.05 ppm/yr | rf_cw.attributes.aging_rate_first_year | WRONG — belongs on reference_clock |
51
+ | ... | ... | ... |
52
+ | 10 MHz ref out: ≥5 dBm, 50 Ω, BNC | NOT FOUND | MISSING |
53
+ ```
54
+
55
+ Every inventory row MUST appear. If a row has no corresponding YAML, write "NOT FOUND". If it maps to the wrong place, write "WRONG — reason".
56
+
57
+ This trace is your working document. The checks below operate on it.
58
+ </step>
59
+
60
+ <step id="3" name="Semantic Checks">
61
+
62
+ Using your trace table, perform ONLY these 5 checks. Each has an explicit pass/fail criterion. Do NOT flag anything outside these 5 checks.
63
+
64
+ ### 1. Placement — right role?
65
+
66
+ For each inventory spec row, verify the role assignment using these rules ONLY:
67
+
68
+ | Fail if... | Example |
69
+ |------------|---------|
70
+ | An accuracy spec (±% rdg/range/abs) is a flat attribute | `frequency_accuracy: {value: 0.01}` instead of `signals.frequency.accuracy` |
71
+ | A resolution spec (digits/bits/increment) is a flat attribute | `resolution_digits: {value: 6.5}` instead of `signals.X.resolution` |
72
+ | A min/max range is flat attribute pairs | `freq_min` + `freq_max` instead of `conditions.frequency.range` |
73
+ | A USER-SELECTABLE SETTING from inventory is missing from controls | Inventory lists "PLL bandwidth: Wide/Narrow" but no control exists |
74
+ | A `note` field exists on any model | `note: "typical"` — use `qualifier: typical` or remove |
75
+
76
+ Do NOT flag: role choices that are defensible (e.g., fixed impedance as attribute vs condition), option dependencies, or design preferences.
77
+
78
+ ### 2. Enum choice — most specific MeasurementFunction?
79
+
80
+ Check each capability's `function` against the enum list. ONLY flag if a MORE SPECIFIC enum exists in this list:
81
+ ```
82
+ {{ENUM_LIST}}
83
+ ```
84
+
85
+ Do NOT flag if the chosen enum is the most specific available, even if the name isn't a perfect match.
86
+
87
+ ### 3. Capability boundaries — one or two?
88
+
89
+ ONLY flag if a SINGLE capability block uses TWO DIFFERENT MeasurementFunction values that both exist in the enum. For example, a capability with `function: ac_voltage` that also models THD measurements (which has its own `thd` enum).
90
+
91
+ Do NOT flag: multiple capability blocks for the same function (that's a valid pattern for different channel groups or option sets), design opinions about whether content belongs in this file, or cross-instrument relationships.
92
+
93
+ ### 4. SpecBand structure — correct `when` dimensions?
94
+
95
+ For each multi-row table in the inventory (values vary by some condition):
96
+ - FAIL if YAML has NO SpecBands for it (values flattened to attributes or single top-level)
97
+ - FAIL if `when` keys reference a dimension that doesn't match the inventory table's varying column
98
+ - FAIL if `when` values are wrong (missing bands, swapped values, wrong ranges)
99
+
100
+ Do NOT flag: single-value tables, structural preferences, or how option variants are modeled.
101
+
102
+ ### 5. Shared controls scope
103
+
104
+ For each entry in the inventory's USER-SELECTABLE SETTINGS with an "Applies to" column:
105
+ - FAIL if the control is MISSING from a capability listed in "Applies to"
106
+ - FAIL if the control is PRESENT on a capability NOT listed in "Applies to"
107
+
108
+ Do NOT flag: controls the writer added from non-settings inventory rows, or design preferences about which capability "should" own a control.
109
+ </step>
110
+
111
+ <step id="4" name="Fix">
112
+ For each finding, edit the YAML file directly using the Edit tool. Make the smallest possible change.
113
+ After all fixes, validate the YAML loads cleanly.
114
+ </step>
115
+
116
+ ## Return Format
117
+
118
+ ```
119
+ ROW TRACE
120
+ =========
121
+ | Inventory Row | YAML Location | Verdict |
122
+ |---|---|---|
123
+ | <every row> | <where it maps> | OK / WRONG / MISSING |
124
+
125
+ REVIEW REPORT
126
+ =============
127
+ Section: {{SECTION_NAME}}
128
+ Capabilities checked: {{CAPABILITIES}}
129
+ Rows traced: <N>
130
+
131
+ CHECK 1 — Placement: <PASS/FAIL> (<N> findings)
132
+ CHECK 2 — Enum choice: <PASS/FAIL> (<N> findings)
133
+ CHECK 3 — Capability boundaries: <PASS/FAIL> (<N> findings)
134
+ CHECK 4 — SpecBand structure: <PASS/FAIL> (<N> findings)
135
+ CHECK 5 — Shared controls: <PASS/FAIL> (<N> findings)
136
+
137
+ Overall: <N>/5 passing
138
+
139
+ FIXED: <N> issues
140
+ FIXED NOTHING: <if 5/5 passing>
141
+
142
+ --- FINDINGS + FIXES ---
143
+
144
+ [For each finding:]
145
+ - Check #: <which>
146
+ - Issue: <one sentence>
147
+ - Inventory row: <which>
148
+ - Fix applied: <exact edit made — "changed line N from X to Y">
149
+
150
+ --- END REPORT ---
151
+ ```
152
+
153
+ If all 5 checks pass, return `Overall: 5/5 passing` and `FIXED NOTHING`.