@openmixer/plugin-qualify 0.10.1 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +52 -10
  2. package/bin/plugin-qualify.mjs +61 -28
  3. package/dist/clap-loader.d.ts +1 -1
  4. package/dist/clap-loader.js +3 -3
  5. package/dist/clap-loader.js.map +1 -1
  6. package/dist/clap-qualify.d.ts +60 -51
  7. package/dist/clap-qualify.js +143 -91
  8. package/dist/clap-qualify.js.map +1 -1
  9. package/dist/cost-fields.d.ts +26 -0
  10. package/dist/cost-fields.js +30 -0
  11. package/dist/cost-fields.js.map +1 -1
  12. package/dist/hosting-codes.d.ts +1 -0
  13. package/dist/hosting-codes.js +1 -0
  14. package/dist/hosting-codes.js.map +1 -1
  15. package/dist/hosting-suitability.d.ts +22 -3
  16. package/dist/hosting-suitability.js +25 -5
  17. package/dist/hosting-suitability.js.map +1 -1
  18. package/dist/index.d.ts +5 -0
  19. package/dist/index.js +5 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/judge-cli.d.ts +41 -0
  22. package/dist/judge-cli.js +114 -0
  23. package/dist/judge-cli.js.map +1 -0
  24. package/dist/measurement/cli.d.ts +7 -0
  25. package/dist/measurement/cli.js +14 -0
  26. package/dist/measurement/cli.js.map +1 -1
  27. package/dist/measurement/format.d.ts +44 -4
  28. package/dist/measurement/format.js +46 -3
  29. package/dist/measurement/format.js.map +1 -1
  30. package/dist/measurement/probe-json.js +4 -0
  31. package/dist/measurement/probe-json.js.map +1 -1
  32. package/dist/measurement/sweep-jsonl.js +2 -1
  33. package/dist/measurement/sweep-jsonl.js.map +1 -1
  34. package/dist/measurement/vocabulary.d.ts +9 -0
  35. package/dist/measurement/vocabulary.js +33 -0
  36. package/dist/measurement/vocabulary.js.map +1 -1
  37. package/dist/probe-judge.d.ts +65 -0
  38. package/dist/probe-judge.js +217 -0
  39. package/dist/probe-judge.js.map +1 -0
  40. package/dist/probe-output-fixtures.d.ts +25 -0
  41. package/dist/probe-output-fixtures.js +134 -0
  42. package/dist/probe-output-fixtures.js.map +1 -0
  43. package/dist/probe-output.d.ts +153 -0
  44. package/dist/probe-output.js +374 -0
  45. package/dist/probe-output.js.map +1 -0
  46. package/dist/probe-runner.d.ts +79 -0
  47. package/dist/probe-runner.js +191 -0
  48. package/dist/probe-runner.js.map +1 -0
  49. package/dist/qualification-record.d.ts +82 -0
  50. package/dist/qualification-record.js +85 -0
  51. package/dist/qualification-record.js.map +1 -0
  52. package/dist/qualify-cli.js +1 -1
  53. package/dist/qualify-cli.js.map +1 -1
  54. package/dist/qualify-declarations.d.ts +11 -2
  55. package/dist/qualify-declarations.js +14 -4
  56. package/dist/qualify-declarations.js.map +1 -1
  57. package/fixtures/clap-scan/fake.json +30 -6
  58. package/fixtures/probe-output/memory-limit-refused.json +190 -0
  59. package/fixtures/probe-output/plugin-crash.json +236 -0
  60. package/fixtures/probe-output/success-msi.json +363 -0
  61. package/package.json +5 -1
  62. package/src/clap-loader.ts +3 -2
  63. package/src/clap-qualify.ts +179 -138
  64. package/src/cost-fields.ts +39 -0
  65. package/src/hosting-codes.ts +1 -0
  66. package/src/hosting-suitability.ts +42 -7
  67. package/src/index.ts +5 -0
  68. package/src/judge-cli.ts +133 -0
  69. package/src/measurement/cli.ts +20 -0
  70. package/src/measurement/format.ts +80 -2
  71. package/src/measurement/probe-json.ts +4 -0
  72. package/src/measurement/sweep-jsonl.ts +2 -1
  73. package/src/measurement/vocabulary.ts +38 -0
  74. package/src/probe-judge.ts +272 -0
  75. package/src/probe-output-fixtures.ts +146 -0
  76. package/src/probe-output.ts +511 -0
  77. package/src/probe-runner.ts +244 -0
  78. package/src/qualification-record.ts +149 -0
  79. package/src/qualify-cli.ts +1 -1
  80. package/src/qualify-declarations.ts +16 -4
  81. package/tools/benchmark.py +116 -13
  82. package/tools/lv2-measure.mjs +2 -0
@@ -0,0 +1,363 @@
1
+ {
2
+ "format": "plugin-hostd.probe-output",
3
+ "formatVersion": "1.0",
4
+ "run": {
5
+ "id": "msi-20261017T221500Z-3569027",
6
+ "startedAt": "2026-10-17T22:15:00+02:00",
7
+ "elapsedMs": 184220,
8
+ "complete": true,
9
+ "outcome": "probe.ok",
10
+ "reason": "reference",
11
+ "protocol": {
12
+ "name": "plugin-hostd.probe-protocol",
13
+ "version": 1
14
+ },
15
+ "tools": {
16
+ "runner": "plugin-hostd-probe 0.1.0",
17
+ "child": "plugin-hostd-probe-clap 0.1.0",
18
+ "clapCore": "0.9.0",
19
+ "interposer": "rt-interpose 1"
20
+ },
21
+ "via": "runner"
22
+ },
23
+ "plugin": {
24
+ "format": "clap",
25
+ "id": "org.example.plate",
26
+ "name": "Plate",
27
+ "vendor": "Example",
28
+ "version": "1.4.2",
29
+ "ownerPackage": "example-plate-1.4.2-1.fc44.x86_64"
30
+ },
31
+ "binary": {
32
+ "path": "/usr/lib64/clap/example-plate.clap",
33
+ "sha256": "356902794a4eec2122989e072271ef995968131145db918d9a3084ce582f244b",
34
+ "files": [
35
+ {
36
+ "path": "example-plate.clap",
37
+ "sha256": "356902794a4eec2122989e072271ef995968131145db918d9a3084ce582f244b"
38
+ }
39
+ ],
40
+ "layout": {
41
+ "scheme": "omx-layout/1",
42
+ "sha256": "0a3e01399262321514e05af0575ebb0b207a35567ac262a060fde655ee069805"
43
+ }
44
+ },
45
+ "descriptor": {
46
+ "path": "descriptors/2/clap/org.example.plate@1.4.2-356902794a4e.json",
47
+ "sha256": "cc312bdd5a9aa62796ebcb5a648c354c5ee45a6a99892425495ccb58a31bc44e",
48
+ "bytes": 9412
49
+ },
50
+ "machine": {
51
+ "class": {
52
+ "arch": "x86_64",
53
+ "family": "intel",
54
+ "coreBand": "17-32",
55
+ "clockBand": "4.5GHz+",
56
+ "preemptRt": false,
57
+ "cstatesLimited": true
58
+ },
59
+ "profile": {
60
+ "governor": "performance",
61
+ "turbo": true,
62
+ "smt": true,
63
+ "preempt": "PREEMPT_DYNAMIC",
64
+ "cpuidle": [
65
+ {
66
+ "cpu": 22,
67
+ "state": "POLL",
68
+ "latencyUs": 0,
69
+ "disabled": false,
70
+ "usageDelta": 118
71
+ },
72
+ {
73
+ "cpu": 22,
74
+ "state": "C1_ACPI",
75
+ "latencyUs": 1,
76
+ "disabled": false,
77
+ "usageDelta": 40210
78
+ },
79
+ {
80
+ "cpu": 22,
81
+ "state": "C2_ACPI",
82
+ "latencyUs": 127,
83
+ "disabled": true,
84
+ "usageDelta": 0
85
+ },
86
+ {
87
+ "cpu": 22,
88
+ "state": "C3_ACPI",
89
+ "latencyUs": 1048,
90
+ "disabled": true,
91
+ "usageDelta": 0
92
+ }
93
+ ],
94
+ "meetsProtocol": true,
95
+ "declaredName": "omx-live-rig"
96
+ },
97
+ "pinnedCpus": "22",
98
+ "reference": {
99
+ "rig": "msi",
100
+ "image": "omx-ref-2026-10"
101
+ }
102
+ },
103
+ "offer": {
104
+ "id": "omx-clap-host",
105
+ "clapExtensions": [
106
+ "clap.audio-ports",
107
+ "clap.latency",
108
+ "clap.log",
109
+ "clap.params",
110
+ "clap.state",
111
+ "clap.thread-check",
112
+ "clap.preset-load/2",
113
+ "clap.track-info/1",
114
+ "clap.remote-controls/2"
115
+ ],
116
+ "realtime": "none"
117
+ },
118
+ "limits": {
119
+ "set": "default",
120
+ "applied": [
121
+ {
122
+ "limit": "wall-clock",
123
+ "value": 600,
124
+ "unit": "s",
125
+ "by": "supervisor"
126
+ },
127
+ {
128
+ "limit": "cpu-time",
129
+ "value": 540,
130
+ "unit": "s",
131
+ "by": "rlimit"
132
+ },
133
+ {
134
+ "limit": "memory",
135
+ "value": 2147483648,
136
+ "unit": "bytes",
137
+ "by": "cgroup"
138
+ },
139
+ {
140
+ "limit": "tasks",
141
+ "value": 64,
142
+ "unit": "count",
143
+ "by": "cgroup"
144
+ },
145
+ {
146
+ "limit": "files",
147
+ "value": 256,
148
+ "unit": "count",
149
+ "by": "rlimit"
150
+ },
151
+ {
152
+ "limit": "file-size",
153
+ "value": 67108864,
154
+ "unit": "bytes",
155
+ "by": "rlimit"
156
+ },
157
+ {
158
+ "limit": "core-dump",
159
+ "value": 0,
160
+ "unit": "bytes",
161
+ "by": "rlimit"
162
+ },
163
+ {
164
+ "limit": "rt-priority",
165
+ "value": 0,
166
+ "by": "rlimit"
167
+ },
168
+ {
169
+ "limit": "cpus",
170
+ "value": "22",
171
+ "by": "affinity"
172
+ },
173
+ {
174
+ "limit": "no-new-privs",
175
+ "by": "prctl"
176
+ },
177
+ {
178
+ "limit": "network",
179
+ "value": "none",
180
+ "by": "netns"
181
+ }
182
+ ],
183
+ "unavailable": []
184
+ },
185
+ "steps": [
186
+ {
187
+ "step": "hash",
188
+ "outcome": "probe.ok",
189
+ "elapsedMs": 4
190
+ },
191
+ {
192
+ "step": "instantiate",
193
+ "outcome": "probe.ok",
194
+ "elapsedMs": 31
195
+ },
196
+ {
197
+ "step": "lifecycle",
198
+ "outcome": "probe.ok",
199
+ "elapsedMs": 2210
200
+ },
201
+ {
202
+ "step": "latency",
203
+ "rate": 48000,
204
+ "quantum": 128,
205
+ "outcome": "probe.ok",
206
+ "elapsedMs": 310
207
+ },
208
+ {
209
+ "step": "cost",
210
+ "rate": 48000,
211
+ "quantum": 128,
212
+ "outcome": "probe.ok",
213
+ "elapsedMs": 30020
214
+ },
215
+ {
216
+ "step": "rt-safety",
217
+ "rate": 48000,
218
+ "quantum": 128,
219
+ "outcome": "probe.ok",
220
+ "elapsedMs": 4100
221
+ },
222
+ {
223
+ "step": "latency",
224
+ "rate": 96000,
225
+ "quantum": 128,
226
+ "outcome": "probe.ok",
227
+ "elapsedMs": 305
228
+ },
229
+ {
230
+ "step": "cost",
231
+ "rate": 96000,
232
+ "quantum": 128,
233
+ "outcome": "probe.ok",
234
+ "elapsedMs": 30011
235
+ },
236
+ {
237
+ "step": "rt-safety",
238
+ "rate": 96000,
239
+ "quantum": 128,
240
+ "outcome": "probe.ok",
241
+ "elapsedMs": 4080
242
+ },
243
+ {
244
+ "step": "note-sweep",
245
+ "outcome": "probe.not-attempted",
246
+ "elapsedMs": 0,
247
+ "detail": "no note input"
248
+ }
249
+ ],
250
+ "grid": [
251
+ {
252
+ "rate": 48000,
253
+ "quantum": 128,
254
+ "outcome": "probe.ok",
255
+ "latency": {
256
+ "declaredFrames": 0,
257
+ "measuredFrames": 0,
258
+ "method": "impulse-onset"
259
+ },
260
+ "cost": {
261
+ "unit": "ns-per-sample",
262
+ "median": 41.2,
263
+ "percentile": {
264
+ "p": 95,
265
+ "value": 47.9
266
+ },
267
+ "min": 39.8,
268
+ "max": 112.4,
269
+ "iqr": 3.1,
270
+ "blocks": 11250,
271
+ "warmupBlocks": 64,
272
+ "warmupMedian": 58.0,
273
+ "timingFloorNsPerBlock": 180
274
+ },
275
+ "rtSafety": {
276
+ "interposer": true,
277
+ "swept": true,
278
+ "sweepApplicable": true,
279
+ "blocks": 512,
280
+ "allocations": 0,
281
+ "locks": 0,
282
+ "syscalls": 0,
283
+ "threadViolations": 0,
284
+ "processErrors": 0,
285
+ "events": []
286
+ }
287
+ },
288
+ {
289
+ "rate": 96000,
290
+ "quantum": 128,
291
+ "outcome": "probe.ok",
292
+ "latency": {
293
+ "declaredFrames": 0,
294
+ "measuredFrames": 0,
295
+ "method": "impulse-onset"
296
+ },
297
+ "cost": {
298
+ "unit": "ns-per-sample",
299
+ "median": 40.7,
300
+ "percentile": {
301
+ "p": 95,
302
+ "value": 46.3
303
+ },
304
+ "min": 39.1,
305
+ "max": 98.0,
306
+ "iqr": 2.8,
307
+ "blocks": 22500,
308
+ "warmupBlocks": 64,
309
+ "timingFloorNsPerBlock": 180,
310
+ "samples": {
311
+ "name": "cost-96000-128",
312
+ "path": "probes/org.example.plate@1.4.2-356902794a4e.cost-96000-128.bin",
313
+ "sha256": "5f649130dafd22f1edc70441f9455415d0856f0f7d26cf7274463b82ac2c5813",
314
+ "bytes": 180000
315
+ }
316
+ },
317
+ "rtSafety": {
318
+ "interposer": true,
319
+ "swept": true,
320
+ "sweepApplicable": true,
321
+ "blocks": 512,
322
+ "allocations": 0,
323
+ "locks": 0,
324
+ "syscalls": 0,
325
+ "threadViolations": 0,
326
+ "processErrors": 0,
327
+ "events": []
328
+ }
329
+ }
330
+ ],
331
+ "behaviour": {
332
+ "lifecycle": {
333
+ "cycles": 30,
334
+ "instantiated": 30,
335
+ "failed": 0
336
+ },
337
+ "threads": {
338
+ "before": 2,
339
+ "afterFirstInstantiate": 2,
340
+ "afterAllFreed": 2
341
+ },
342
+ "memory": {
343
+ "rssStartKb": 9120,
344
+ "rssMaxKb": 14988
345
+ },
346
+ "features": {
347
+ "extensionsAsked": [
348
+ "clap.audio-ports",
349
+ "clap.params",
350
+ "clap.state",
351
+ "clap.latency"
352
+ ]
353
+ }
354
+ },
355
+ "logs": [
356
+ {
357
+ "name": "stderr",
358
+ "path": "probes/org.example.plate@1.4.2-356902794a4e.stderr.log",
359
+ "sha256": "c46928bc87de23b9a8bd235aa1fe67ccb1542c8389ad3f02bf4ab5cff506e98f",
360
+ "bytes": 212
361
+ }
362
+ ]
363
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openmixer/plugin-qualify",
3
- "version": "0.10.1",
3
+ "version": "0.12.0",
4
4
  "description": "Qualify audio plugins for real-time hosting: scan, offline latency and cost measurement, a mod-host hosting sweep, and a fail-closed rating.",
5
5
  "type": "module",
6
6
  "license": "GPL-3.0-or-later",
@@ -67,6 +67,7 @@
67
67
  "dist",
68
68
  "src",
69
69
  "!src/**/*.test.ts",
70
+ "!src/**/*.support.*",
70
71
  "tools",
71
72
  "!tools/test_*.py",
72
73
  "!**/__pycache__",
@@ -93,5 +94,8 @@
93
94
  "publishConfig": {
94
95
  "access": "public",
95
96
  "provenance": true
97
+ },
98
+ "dependencies": {
99
+ "@openmixer/omx-contract": "^2.16.0"
96
100
  }
97
101
  }
@@ -25,6 +25,7 @@ import {
25
25
  CLAP_SCAN_TOOL_DEFAULT,
26
26
  CLAP_SCAN_TOOL_ENV,
27
27
  CLAP_SYSTEM_DIR,
28
+ CLAP_SYSTEM_DIR_ENV,
28
29
  CLAP_USER_DIR,
29
30
  } from "./qualify-declarations.js";
30
31
 
@@ -428,11 +429,11 @@ export function clapLoader(options: ClapLoaderOptions = {}): PluginLoader {
428
429
 
429
430
  /**
430
431
  * The directories `--all` walks, in order and once each: every non-empty entry of `CLAP_PATH`, then
431
- * `~/.clap`, then `/usr/lib/clap`.
432
+ * `~/.clap`, then `/usr/lib/clap` (or the directory `OMX_CLAP_SYSTEM_DIR` names).
432
433
  */
433
434
  export function clapSearchPath(env: Readonly<Record<string, string | undefined>>, home: string): string[] {
434
435
  const named = (env[CLAP_PATH_ENV] ?? "").split(":").filter((d) => d !== "");
435
- return [...new Set([...named, join(home, CLAP_USER_DIR), CLAP_SYSTEM_DIR].map((d) => resolve(d)))];
436
+ return [...new Set([...named, join(home, CLAP_USER_DIR), env[CLAP_SYSTEM_DIR_ENV] || CLAP_SYSTEM_DIR].map((d) => resolve(d)))];
436
437
  }
437
438
 
438
439
  export interface ClapDiscoverOptions extends ClapLoaderOptions {