@openmixer/plugin-qualify 0.0.0-stage → 0.3.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 (114) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +203 -2
  3. package/bin/plugin-qualify.mjs +77 -0
  4. package/dist/clap-loader.d.ts +147 -0
  5. package/dist/clap-loader.js +252 -0
  6. package/dist/clap-loader.js.map +1 -0
  7. package/dist/clap-qualify.d.ts +126 -0
  8. package/dist/clap-qualify.js +272 -0
  9. package/dist/clap-qualify.js.map +1 -0
  10. package/dist/host-profiles.d.ts +42 -0
  11. package/dist/host-profiles.js +106 -0
  12. package/dist/host-profiles.js.map +1 -0
  13. package/dist/hosting-codes.d.ts +62 -0
  14. package/dist/hosting-codes.js +72 -0
  15. package/dist/hosting-codes.js.map +1 -0
  16. package/dist/hosting-suitability.d.ts +354 -0
  17. package/dist/hosting-suitability.js +654 -0
  18. package/dist/hosting-suitability.js.map +1 -0
  19. package/dist/index.d.ts +17 -0
  20. package/dist/index.js +20 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/loader.d.ts +26 -0
  23. package/dist/loader.js +9 -0
  24. package/dist/loader.js.map +1 -0
  25. package/dist/lv2-loader.d.ts +7 -0
  26. package/dist/lv2-loader.js +50 -0
  27. package/dist/lv2-loader.js.map +1 -0
  28. package/dist/measurement/cli.d.ts +168 -0
  29. package/dist/measurement/cli.js +353 -0
  30. package/dist/measurement/cli.js.map +1 -0
  31. package/dist/measurement/fixtures.d.ts +23 -0
  32. package/dist/measurement/fixtures.js +129 -0
  33. package/dist/measurement/fixtures.js.map +1 -0
  34. package/dist/measurement/format.d.ts +483 -0
  35. package/dist/measurement/format.js +627 -0
  36. package/dist/measurement/format.js.map +1 -0
  37. package/dist/measurement/guards.d.ts +33 -0
  38. package/dist/measurement/guards.js +61 -0
  39. package/dist/measurement/guards.js.map +1 -0
  40. package/dist/measurement/index.d.ts +36 -0
  41. package/dist/measurement/index.js +39 -0
  42. package/dist/measurement/index.js.map +1 -0
  43. package/dist/measurement/merge.d.ts +143 -0
  44. package/dist/measurement/merge.js +315 -0
  45. package/dist/measurement/merge.js.map +1 -0
  46. package/dist/measurement/plan.d.ts +127 -0
  47. package/dist/measurement/plan.js +141 -0
  48. package/dist/measurement/plan.js.map +1 -0
  49. package/dist/measurement/probe-json.d.ts +61 -0
  50. package/dist/measurement/probe-json.js +253 -0
  51. package/dist/measurement/probe-json.js.map +1 -0
  52. package/dist/measurement/provenance.d.ts +91 -0
  53. package/dist/measurement/provenance.js +173 -0
  54. package/dist/measurement/provenance.js.map +1 -0
  55. package/dist/measurement/sweep-jsonl.d.ts +40 -0
  56. package/dist/measurement/sweep-jsonl.js +154 -0
  57. package/dist/measurement/sweep-jsonl.js.map +1 -0
  58. package/dist/measurement/vocabulary.d.ts +125 -0
  59. package/dist/measurement/vocabulary.js +217 -0
  60. package/dist/measurement/vocabulary.js.map +1 -0
  61. package/dist/qualify-cli.d.ts +83 -0
  62. package/dist/qualify-cli.js +224 -0
  63. package/dist/qualify-cli.js.map +1 -0
  64. package/dist/qualify-declarations.d.ts +98 -0
  65. package/dist/qualify-declarations.js +76 -0
  66. package/dist/qualify-declarations.js.map +1 -0
  67. package/dist/qualify-options.d.ts +22 -0
  68. package/dist/qualify-options.js +36 -0
  69. package/dist/qualify-options.js.map +1 -0
  70. package/dist/rating.d.ts +32 -0
  71. package/dist/rating.js +30 -0
  72. package/dist/rating.js.map +1 -0
  73. package/dist/tool-paths.d.ts +12 -0
  74. package/dist/tool-paths.js +29 -0
  75. package/dist/tool-paths.js.map +1 -0
  76. package/fixtures/clap-scan/controls.json +8 -0
  77. package/fixtures/clap-scan/fake.json +16 -0
  78. package/fixtures/clap-scan/mixed.json +18 -0
  79. package/fixtures/zero-path.lv2/manifest.ttl +3 -0
  80. package/fixtures/zero-path.lv2/zero-path.c +85 -0
  81. package/fixtures/zero-path.lv2/zero-path.ttl +21 -0
  82. package/package.json +91 -3
  83. package/src/clap-loader.ts +393 -0
  84. package/src/clap-qualify.ts +387 -0
  85. package/src/host-profiles.ts +122 -0
  86. package/src/hosting-codes.ts +71 -0
  87. package/src/hosting-suitability.ts +982 -0
  88. package/src/index.ts +19 -0
  89. package/src/loader.ts +30 -0
  90. package/src/lv2-loader.ts +50 -0
  91. package/src/measurement/cli.ts +458 -0
  92. package/src/measurement/fixtures.ts +141 -0
  93. package/src/measurement/format.ts +1064 -0
  94. package/src/measurement/guards.ts +64 -0
  95. package/src/measurement/index.ts +39 -0
  96. package/src/measurement/merge.ts +434 -0
  97. package/src/measurement/plan.ts +219 -0
  98. package/src/measurement/probe-json.ts +271 -0
  99. package/src/measurement/provenance.ts +220 -0
  100. package/src/measurement/sweep-jsonl.ts +173 -0
  101. package/src/measurement/vocabulary.ts +298 -0
  102. package/src/qualify-cli.ts +277 -0
  103. package/src/qualify-declarations.ts +117 -0
  104. package/src/qualify-options.ts +49 -0
  105. package/src/rating.ts +53 -0
  106. package/src/tool-paths.ts +32 -0
  107. package/tools/_declarations.py +21 -0
  108. package/tools/benchmark.py +2462 -0
  109. package/tools/gen-python-declarations.d.mts +4 -0
  110. package/tools/gen-python-declarations.mjs +92 -0
  111. package/tools/hosting-sweep.mjs +51 -0
  112. package/tools/lv2-measure.mjs +204 -0
  113. package/tools/lv2_presets.py +132 -0
  114. package/tools/scan.py +432 -0
@@ -0,0 +1,49 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * The `plugin-qualify` CLI's OPTIONS, declared once. The parser, `--help` and the tests all read this table; every default is a declaration
5
+ * from `declarations.ts`, never a literal here.
6
+ */
7
+ import { QUALIFY_QUANTA, QUALIFY_RATES } from "./qualify-declarations.js";
8
+ import { HOST_PROFILES, OPENMIXER_CONSOLE_PROFILE } from "./host-profiles.js";
9
+
10
+ /** How the result is printed. `text` = plugin, verdict, the reason that decided it. */
11
+ export const OUTPUT_FORMATS = ["json", "text"] as const;
12
+ export type OutputFormat = (typeof OUTPUT_FORMATS)[number];
13
+
14
+ /** The exit codes, as the spec states them. */
15
+ export const EXIT_CODE = {
16
+ /** Every named plugin rated `suitable`. */
17
+ allQualified: 0,
18
+ /** At least one plugin measured and rated below `suitable`. */
19
+ someNotQualified: 1,
20
+ /** A plugin could not be measured, or the arguments/targets could not be resolved. */
21
+ couldNotMeasure: 2,
22
+ } as const;
23
+
24
+ export interface QualifyOption {
25
+ /** `--rates`; a positional is not an option. */
26
+ readonly flag: string;
27
+ /** The value's name when the option takes one. */
28
+ readonly value?: string;
29
+ readonly describe: string;
30
+ /** The declared default, printed by `--help` — absent for a switch. */
31
+ readonly default?: string;
32
+ }
33
+
34
+ export const QUALIFY_OPTIONS: readonly QualifyOption[] = [
35
+ { flag: "--all", describe: "every plugin lilv finds (LV2_PATH honoured)" },
36
+ { flag: "--rates", value: "list", describe: "sample rates to measure at, comma-separated", default: QUALIFY_RATES.join(",") },
37
+ { flag: "--quanta", value: "list", describe: "quanta (frames) to rate cost at, comma-separated", default: QUALIFY_QUANTA.join(",") },
38
+ { flag: "--out", value: "dir", describe: "write one interchange JSON document per run into this directory" },
39
+ { flag: "--format", value: OUTPUT_FORMATS.join("|"), describe: "json = the verdicts as JSON; text = plugin, verdict, deciding reason", default: "text" },
40
+ { flag: "--isolate", describe: "a fresh worker per plugin, so a crash or hang takes only that plugin" },
41
+ { flag: "--no-host-sweep", describe: "offline lilv measurement only; no mod-host hosting sweep" },
42
+ {
43
+ flag: "--host-profile",
44
+ value: "file|id",
45
+ describe: `judge against this host (${HOST_PROFILES.map((p) => p.id).join(", ")}, or a profile JSON file); repeat or comma-separate for one verdict per profile`,
46
+ default: OPENMIXER_CONSOLE_PROFILE.id,
47
+ },
48
+ { flag: "--help", describe: "this text" },
49
+ ];
package/src/rating.ts ADDED
@@ -0,0 +1,53 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ //
4
+ // The rating vocabulary every verdict speaks: four ratings, their severity order, the
5
+ // worst-wins fold, and whether a reason is physics or taste.
6
+
7
+ import type { VerdictRating } from "./measurement/vocabulary.js";
8
+
9
+ /**
10
+ * How well a plugin fits a destination role. The four words are the interchange's
11
+ * (`VERDICT_RATINGS`, `measurement/vocabulary.ts`), so a written verdict speaks this vocabulary.
12
+ *
13
+ * - `suitable` — every dimension resolved and inside its budget.
14
+ * - `conditional` — nothing objectively disqualifies it, but something needs the operator's
15
+ * attention: a taste warning, a topology difference, a look-ahead control that can be
16
+ * turned up past the budget, a cost that eats most of the allowance.
17
+ * - `unknown` — an OBJECTIVE dimension could not be decided because the measurement is
18
+ * missing or does not resolve at this rate. Not a pass and not a failure: an admission.
19
+ * - `unsuitable` — an objective dimension failed on measured evidence.
20
+ */
21
+ export type SuitabilityRating = VerdictRating;
22
+
23
+ /**
24
+ * Severity order for folding several reasons into one verdict:
25
+ * `unsuitable` > `unknown` > `conditional` > `suitable`.
26
+ *
27
+ * `unknown` outranks `conditional` on purpose. A conditional plugin is one the console has
28
+ * fully measured and has an opinion about; an unknown one is a plugin the console cannot
29
+ * vouch for at all. Reporting "there is a caution" while an objective dimension is
30
+ * un-measured would present the smaller finding as the whole story.
31
+ */
32
+ export const RATING_SEVERITY: Readonly<Record<SuitabilityRating, number>> = {
33
+ suitable: 0,
34
+ conditional: 1,
35
+ unknown: 2,
36
+ unsuitable: 3,
37
+ };
38
+
39
+ /** The worst (most severe) of some ratings; `suitable` for an empty list. */
40
+ export function worstRating(ratings: readonly SuitabilityRating[]): SuitabilityRating {
41
+ let worst: SuitabilityRating = "suitable";
42
+ for (const rating of ratings) {
43
+ if (RATING_SEVERITY[rating] > RATING_SEVERITY[worst]) worst = rating;
44
+ }
45
+ return worst;
46
+ }
47
+
48
+ /**
49
+ * Physics or taste. The distinction drives what a reason is ALLOWED to do
50
+ * (`contributedRating` in the catalog, `contributedHostingRating` here) and, downstream, whether an operator override is a formality
51
+ * or a decision — conflating them is how a tool becomes either nagging or dangerous.
52
+ */
53
+ export type SuitabilityKind = "objective" | "advisory";
@@ -0,0 +1,32 @@
1
+ // SPDX-License-Identifier: GPL-3.0-or-later
2
+ // Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ /**
4
+ * Where the package's own tools live, resolved from this module so it follows the package
5
+ * wherever it is installed (a checkout, an RPM's bundled node_modules, a pnpm store). The
6
+ * tools are shipped RUNTIME artefacts, not dev scripts.
7
+ */
8
+ import { fileURLToPath } from "node:url";
9
+
10
+ /**
11
+ * `tools/` — `scan.py`, `benchmark.py`, `lv2-measure.mjs`, `hosting-sweep.mjs`. Resolved when a
12
+ * console asks, never at import: a consumer that only reads this package's declarations from a
13
+ * browser-like module graph (web-ui's conformance suites, `http:` module URLs) must load it.
14
+ */
15
+ export function toolsDir(): string {
16
+ return fileURLToPath(new URL("../tools/", import.meta.url));
17
+ }
18
+
19
+ /** The measurement runner a console spawns for Setup > Plugin analysis. */
20
+ export function lv2MeasureToolPath(): string {
21
+ return fileURLToPath(new URL("../tools/lv2-measure.mjs", import.meta.url));
22
+ }
23
+
24
+ /** The package's own build of the CLAP prober (`make -C native`). */
25
+ export function clapQualifyToolPath(): string {
26
+ return fileURLToPath(new URL("../native/build/clap-qualify", import.meta.url));
27
+ }
28
+
29
+ /** The package's own build of the interposer the CLAP prober runs under. */
30
+ export function rtInterposePath(): string {
31
+ return fileURLToPath(new URL("../native/build/rt_interpose.so", import.meta.url));
32
+ }
@@ -0,0 +1,21 @@
1
+ # SPDX-License-Identifier: GPL-3.0-or-later
2
+ # Copyright (C) 2026 Pau Aliagas <linuxnow@gmail.com>
3
+ #
4
+ # GENERATED by tools/gen-python-declarations.mjs — do not hand-edit.
5
+ #
6
+ # Source: src/qualify-declarations.ts. The Python tools cannot import a TS module, so this file
7
+ # stands in for that import: regenerated and checked byte-identical instead of a second,
8
+ # hand-typed copy of the figures (2026-09-17 declare-derive audit, F8).
9
+ #
10
+ # Regenerate: node tools/gen-python-declarations.mjs --write
11
+ # Verify: node tools/gen-python-declarations.mjs --check
12
+
13
+ COST_REFERENCE_RATE = 96000
14
+ QUANTUM_FRAMES = 1024
15
+ MEASURE_BASE_RATE = 48000
16
+ OPERATIONAL_RATE_FLOOR = 48000
17
+ QUALIFY_RATES = (44100, 48000, 96000, 192000)
18
+ QUALIFY_QUANTA = (128, 256, 512, 1024)
19
+ PLUGIN_TIMEOUT_S = 15
20
+ BOOT_TIMEOUT_S = 120
21
+ COST_TIMEOUT_S = 60