@lovrozagar/oat 0.10.0 → 0.11.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 (278) hide show
  1. package/README.md +25 -2006
  2. package/dist/cli.js +283 -59
  3. package/dist/config/define-config.d.ts +8 -0
  4. package/dist/config/define-config.d.ts.map +1 -1
  5. package/dist/config/define-config.js.map +1 -1
  6. package/dist/config/validate.d.ts +12 -0
  7. package/dist/config/validate.d.ts.map +1 -0
  8. package/dist/config/validate.js +86 -0
  9. package/dist/config/validate.js.map +1 -0
  10. package/dist/conformance/effects.d.ts +9 -0
  11. package/dist/conformance/effects.d.ts.map +1 -0
  12. package/dist/conformance/effects.js +276 -0
  13. package/dist/conformance/effects.js.map +1 -0
  14. package/dist/conformance/expected-failures.d.ts +18 -0
  15. package/dist/conformance/expected-failures.d.ts.map +1 -0
  16. package/dist/conformance/expected-failures.js +48 -0
  17. package/dist/conformance/expected-failures.js.map +1 -0
  18. package/dist/conformance/feature-gate.d.ts +7 -0
  19. package/dist/conformance/feature-gate.d.ts.map +1 -0
  20. package/dist/conformance/feature-gate.js +428 -0
  21. package/dist/conformance/feature-gate.js.map +1 -0
  22. package/dist/conformance/fuzz.d.ts +108 -0
  23. package/dist/conformance/fuzz.d.ts.map +1 -0
  24. package/dist/conformance/fuzz.js +246 -0
  25. package/dist/conformance/fuzz.js.map +1 -0
  26. package/dist/conformance/leaks.d.ts +10 -0
  27. package/dist/conformance/leaks.d.ts.map +1 -0
  28. package/dist/conformance/leaks.js +23 -0
  29. package/dist/conformance/leaks.js.map +1 -0
  30. package/dist/conformance/pool.d.ts +49 -0
  31. package/dist/conformance/pool.d.ts.map +1 -0
  32. package/dist/conformance/pool.js +75 -0
  33. package/dist/conformance/pool.js.map +1 -0
  34. package/dist/conformance/rate-limit.d.ts +7 -0
  35. package/dist/conformance/rate-limit.d.ts.map +1 -0
  36. package/dist/conformance/rate-limit.js +372 -0
  37. package/dist/conformance/rate-limit.js.map +1 -0
  38. package/dist/conformance/scope.d.ts +15 -0
  39. package/dist/conformance/scope.d.ts.map +1 -0
  40. package/dist/conformance/scope.js +78 -0
  41. package/dist/conformance/scope.js.map +1 -0
  42. package/dist/conformance/seed-contract.d.ts +11 -0
  43. package/dist/conformance/seed-contract.d.ts.map +1 -0
  44. package/dist/conformance/seed-contract.js +680 -0
  45. package/dist/conformance/seed-contract.js.map +1 -0
  46. package/dist/conformance/shapes.d.ts +35 -0
  47. package/dist/conformance/shapes.d.ts.map +1 -0
  48. package/dist/conformance/shapes.js +162 -0
  49. package/dist/conformance/shapes.js.map +1 -0
  50. package/dist/conformance/specs.d.ts +21 -0
  51. package/dist/conformance/specs.d.ts.map +1 -0
  52. package/dist/conformance/specs.js +306 -0
  53. package/dist/conformance/specs.js.map +1 -0
  54. package/dist/conformance/suite.d.ts +209 -0
  55. package/dist/conformance/suite.d.ts.map +1 -0
  56. package/dist/conformance/suite.js +1538 -0
  57. package/dist/conformance/suite.js.map +1 -0
  58. package/dist/conformance/unique.d.ts +7 -0
  59. package/dist/conformance/unique.d.ts.map +1 -0
  60. package/dist/conformance/unique.js +586 -0
  61. package/dist/conformance/unique.js.map +1 -0
  62. package/dist/conformance/worker.d.ts +3 -0
  63. package/dist/conformance/worker.d.ts.map +1 -0
  64. package/dist/conformance/worker.js +27 -0
  65. package/dist/conformance/worker.js.map +1 -0
  66. package/dist/index.d.ts +8 -3
  67. package/dist/index.js +5 -2
  68. package/dist/reference/defects.d.ts +71 -1
  69. package/dist/reference/defects.d.ts.map +1 -1
  70. package/dist/reference/defects.js +74 -8
  71. package/dist/reference/defects.js.map +1 -1
  72. package/dist/reference/dialect.d.ts +6 -4
  73. package/dist/reference/dialect.d.ts.map +1 -1
  74. package/dist/reference/dialect.js +1 -0
  75. package/dist/reference/dialect.js.map +1 -1
  76. package/dist/reference/http.d.ts +17 -25
  77. package/dist/reference/http.d.ts.map +1 -1
  78. package/dist/reference/http.js +574 -224
  79. package/dist/reference/http.js.map +1 -1
  80. package/dist/reference/listing.d.ts +51 -0
  81. package/dist/reference/listing.d.ts.map +1 -0
  82. package/dist/reference/listing.js +256 -0
  83. package/dist/reference/listing.js.map +1 -0
  84. package/dist/reference/model.d.ts +35 -1
  85. package/dist/reference/model.d.ts.map +1 -1
  86. package/dist/reference/model.js +42 -0
  87. package/dist/reference/model.js.map +1 -1
  88. package/dist/reference/query.d.ts +132 -43
  89. package/dist/reference/query.d.ts.map +1 -1
  90. package/dist/reference/query.js +397 -315
  91. package/dist/reference/query.js.map +1 -1
  92. package/dist/reference/shapes.d.ts +60 -0
  93. package/dist/reference/shapes.d.ts.map +1 -0
  94. package/dist/reference/shapes.js +142 -0
  95. package/dist/reference/shapes.js.map +1 -0
  96. package/dist/reference/spec.d.ts +9 -2
  97. package/dist/reference/spec.d.ts.map +1 -1
  98. package/dist/reference/spec.js +291 -71
  99. package/dist/reference/spec.js.map +1 -1
  100. package/dist/reference/store-api.d.ts +14 -43
  101. package/dist/reference/store-api.d.ts.map +1 -1
  102. package/dist/reference/store-api.js +8 -58
  103. package/dist/reference/store-api.js.map +1 -1
  104. package/dist/reference/stores/memory.d.ts +12 -15
  105. package/dist/reference/stores/memory.d.ts.map +1 -1
  106. package/dist/reference/stores/memory.js +22 -70
  107. package/dist/reference/stores/memory.js.map +1 -1
  108. package/dist/reference/stores/postgres.d.ts +11 -23
  109. package/dist/reference/stores/postgres.d.ts.map +1 -1
  110. package/dist/reference/stores/postgres.js +53 -334
  111. package/dist/reference/stores/postgres.js.map +1 -1
  112. package/dist/reference/stores/sql-compile.d.ts +36 -0
  113. package/dist/reference/stores/sql-compile.d.ts.map +1 -0
  114. package/dist/reference/stores/sql-compile.js +95 -0
  115. package/dist/reference/stores/sql-compile.js.map +1 -0
  116. package/dist/reference/stores/sqlite.d.ts +12 -27
  117. package/dist/reference/stores/sqlite.d.ts.map +1 -1
  118. package/dist/reference/stores/sqlite.js +54 -355
  119. package/dist/reference/stores/sqlite.js.map +1 -1
  120. package/dist/report/console.d.ts.map +1 -1
  121. package/dist/report/console.js +23 -9
  122. package/dist/report/console.js.map +1 -1
  123. package/dist/report/matrix.d.ts +2 -0
  124. package/dist/report/matrix.d.ts.map +1 -1
  125. package/dist/report/matrix.js +63 -10
  126. package/dist/report/matrix.js.map +1 -1
  127. package/dist/report/render.d.ts +10 -1
  128. package/dist/report/render.d.ts.map +1 -1
  129. package/dist/report/render.js +75 -13
  130. package/dist/report/render.js.map +1 -1
  131. package/dist/runtime/async.d.ts +16 -3
  132. package/dist/runtime/async.d.ts.map +1 -1
  133. package/dist/runtime/async.js +24 -19
  134. package/dist/runtime/async.js.map +1 -1
  135. package/dist/runtime/auth.d.ts +2 -9
  136. package/dist/runtime/auth.d.ts.map +1 -1
  137. package/dist/runtime/auth.js +38 -62
  138. package/dist/runtime/auth.js.map +1 -1
  139. package/dist/runtime/body.d.ts +15 -3
  140. package/dist/runtime/body.d.ts.map +1 -1
  141. package/dist/runtime/body.js +61 -12
  142. package/dist/runtime/body.js.map +1 -1
  143. package/dist/runtime/check-costs.d.ts +15 -0
  144. package/dist/runtime/check-costs.d.ts.map +1 -0
  145. package/dist/runtime/check-costs.js +114 -0
  146. package/dist/runtime/check-costs.js.map +1 -0
  147. package/dist/runtime/check-ids.d.ts +15 -0
  148. package/dist/runtime/check-ids.d.ts.map +1 -0
  149. package/dist/runtime/check-ids.js +140 -0
  150. package/dist/runtime/check-ids.js.map +1 -0
  151. package/dist/runtime/checks.d.ts +83 -20
  152. package/dist/runtime/checks.d.ts.map +1 -1
  153. package/dist/runtime/checks.js +3285 -1947
  154. package/dist/runtime/checks.js.map +1 -1
  155. package/dist/runtime/client.d.ts +112 -0
  156. package/dist/runtime/client.d.ts.map +1 -1
  157. package/dist/runtime/client.js +271 -39
  158. package/dist/runtime/client.js.map +1 -1
  159. package/dist/runtime/cookies.d.ts +16 -2
  160. package/dist/runtime/cookies.d.ts.map +1 -1
  161. package/dist/runtime/cookies.js +83 -22
  162. package/dist/runtime/cookies.js.map +1 -1
  163. package/dist/runtime/exchanges.d.ts +4 -5
  164. package/dist/runtime/exchanges.d.ts.map +1 -1
  165. package/dist/runtime/exchanges.js +33 -55
  166. package/dist/runtime/exchanges.js.map +1 -1
  167. package/dist/runtime/exit.d.ts +40 -0
  168. package/dist/runtime/exit.d.ts.map +1 -0
  169. package/dist/runtime/exit.js +48 -0
  170. package/dist/runtime/exit.js.map +1 -0
  171. package/dist/runtime/feature-gate.d.ts +0 -9
  172. package/dist/runtime/feature-gate.d.ts.map +1 -1
  173. package/dist/runtime/feature-gate.js +0 -21
  174. package/dist/runtime/feature-gate.js.map +1 -1
  175. package/dist/runtime/finding.d.ts +49 -8
  176. package/dist/runtime/finding.d.ts.map +1 -1
  177. package/dist/runtime/finding.js +51 -8
  178. package/dist/runtime/finding.js.map +1 -1
  179. package/dist/runtime/fixture.d.ts +35 -28
  180. package/dist/runtime/fixture.d.ts.map +1 -1
  181. package/dist/runtime/fixture.js +92 -731
  182. package/dist/runtime/fixture.js.map +1 -1
  183. package/dist/runtime/generate.d.ts +63 -0
  184. package/dist/runtime/generate.d.ts.map +1 -0
  185. package/dist/runtime/generate.js +635 -0
  186. package/dist/runtime/generate.js.map +1 -0
  187. package/dist/runtime/headers.d.ts +6 -0
  188. package/dist/runtime/headers.d.ts.map +1 -0
  189. package/dist/runtime/headers.js +16 -0
  190. package/dist/runtime/headers.js.map +1 -0
  191. package/dist/runtime/path.d.ts +7 -0
  192. package/dist/runtime/path.d.ts.map +1 -0
  193. package/dist/runtime/path.js +44 -0
  194. package/dist/runtime/path.js.map +1 -0
  195. package/dist/runtime/payloads.d.ts +2 -0
  196. package/dist/runtime/payloads.d.ts.map +1 -1
  197. package/dist/runtime/payloads.js +2 -1
  198. package/dist/runtime/payloads.js.map +1 -1
  199. package/dist/runtime/rate-limit.d.ts +6 -4
  200. package/dist/runtime/rate-limit.d.ts.map +1 -1
  201. package/dist/runtime/rate-limit.js +22 -33
  202. package/dist/runtime/rate-limit.js.map +1 -1
  203. package/dist/runtime/redact.d.ts +24 -0
  204. package/dist/runtime/redact.d.ts.map +1 -0
  205. package/dist/runtime/redact.js +98 -0
  206. package/dist/runtime/redact.js.map +1 -0
  207. package/dist/runtime/run.d.ts +34 -2
  208. package/dist/runtime/run.d.ts.map +1 -1
  209. package/dist/runtime/run.js +346 -138
  210. package/dist/runtime/run.js.map +1 -1
  211. package/dist/runtime/runs.d.ts +5 -0
  212. package/dist/runtime/runs.d.ts.map +1 -1
  213. package/dist/runtime/runs.js +7 -1
  214. package/dist/runtime/runs.js.map +1 -1
  215. package/dist/runtime/teardown.d.ts +17 -4
  216. package/dist/runtime/teardown.d.ts.map +1 -1
  217. package/dist/runtime/teardown.js +49 -16
  218. package/dist/runtime/teardown.js.map +1 -1
  219. package/dist/runtime/transcript.d.ts +34 -2
  220. package/dist/runtime/transcript.d.ts.map +1 -1
  221. package/dist/runtime/transcript.js +119 -24
  222. package/dist/runtime/transcript.js.map +1 -1
  223. package/dist/runtime/unique.d.ts +2 -11
  224. package/dist/runtime/unique.d.ts.map +1 -1
  225. package/dist/runtime/unique.js +27 -53
  226. package/dist/runtime/unique.js.map +1 -1
  227. package/dist/runtime/validate.d.ts +13 -2
  228. package/dist/runtime/validate.d.ts.map +1 -1
  229. package/dist/runtime/validate.js +51 -31
  230. package/dist/runtime/validate.js.map +1 -1
  231. package/dist/runtime/wait.d.ts +2 -1
  232. package/dist/runtime/wait.d.ts.map +1 -1
  233. package/dist/runtime/wait.js +2 -36
  234. package/dist/runtime/wait.js.map +1 -1
  235. package/dist/runtime/world.d.ts +24 -1
  236. package/dist/runtime/world.d.ts.map +1 -1
  237. package/dist/runtime/world.js +101 -26
  238. package/dist/runtime/world.js.map +1 -1
  239. package/dist/spec/collection.d.ts +8 -2
  240. package/dist/spec/collection.d.ts.map +1 -1
  241. package/dist/spec/collection.js +47 -7
  242. package/dist/spec/collection.js.map +1 -1
  243. package/dist/spec/extensions.d.ts +5 -1
  244. package/dist/spec/extensions.d.ts.map +1 -1
  245. package/dist/spec/extensions.js +9 -2
  246. package/dist/spec/extensions.js.map +1 -1
  247. package/dist/spec/graph.d.ts +46 -0
  248. package/dist/spec/graph.d.ts.map +1 -1
  249. package/dist/spec/graph.js +175 -11
  250. package/dist/spec/graph.js.map +1 -1
  251. package/dist/spec/load.d.ts +25 -5
  252. package/dist/spec/load.d.ts.map +1 -1
  253. package/dist/spec/load.js +160 -59
  254. package/dist/spec/load.js.map +1 -1
  255. package/dist/spec/query-capabilities.d.ts +4 -0
  256. package/dist/spec/query-capabilities.d.ts.map +1 -1
  257. package/dist/spec/query-capabilities.js +6 -0
  258. package/dist/spec/query-capabilities.js.map +1 -1
  259. package/dist/spec/schema.d.ts +20 -0
  260. package/dist/spec/schema.d.ts.map +1 -0
  261. package/dist/spec/schema.js +118 -0
  262. package/dist/spec/schema.js.map +1 -0
  263. package/dist/spec/tag-schema.d.ts +12 -0
  264. package/dist/spec/tag-schema.d.ts.map +1 -0
  265. package/dist/spec/tag-schema.js +143 -0
  266. package/dist/spec/tag-schema.js.map +1 -0
  267. package/dist/spec/types.js +17 -1
  268. package/dist/spec/types.js.map +1 -1
  269. package/docs/api.md +59 -0
  270. package/docs/assumptions.md +99 -0
  271. package/docs/checks.md +183 -0
  272. package/docs/commands.md +214 -0
  273. package/docs/configuration.md +650 -0
  274. package/docs/model.md +184 -0
  275. package/docs/reference-defects.md +94 -0
  276. package/docs/reports.md +211 -0
  277. package/docs/tags.md +400 -0
  278. package/package.json +3 -1
@@ -0,0 +1,246 @@
1
+ /**
2
+ * Combination fuzzing: many defects at once, chosen at random.
3
+ *
4
+ * The defect matrix injects one fault at a time, which is not how a backend fails. Real ones
5
+ * carry several simultaneously, and that interaction is where a tool quietly stops being useful:
6
+ * a broken listing makes every downstream check report a consequence, and a report of thirty
7
+ * findings with one root cause is nearly as useless as a report of none.
8
+ *
9
+ * So the oracle here is not "did every injected defect produce a finding". It is:
10
+ *
11
+ * - **recall** — each injected defect's primary check fired, *or* was legitimately suppressed
12
+ * because a check it depends on was itself broken by another injected defect;
13
+ * - **precision** — no finding outside the union of what the injected set can justify.
14
+ *
15
+ * Suppression is the interesting half. Counting a suppressed check as a miss would push oat
16
+ * toward reporting cascades; counting any suppression as fine would let it hide real defects
17
+ * behind unrelated ones. The dependency graph is what separates those two, so it is consulted
18
+ * rather than assumed.
19
+ */
20
+ import { CHECKS } from "../runtime/checks.js";
21
+ import { run } from "../runtime/run.js";
22
+ import { EXPECTED, PRINCIPALS, defectsFor } from "./suite.js";
23
+ /** Deterministic PRNG so a failing case can be replayed from its seed alone. */
24
+ function rng(seed) {
25
+ let state = seed >>> 0;
26
+ return () => {
27
+ state = (state * 1_664_525 + 1_013_904_223) >>> 0;
28
+ return state / 0x1_00_00_00_00;
29
+ };
30
+ }
31
+ function primary(defect) {
32
+ const expected = EXPECTED[defect];
33
+ return Array.isArray(expected) ? (expected[0] ?? "") : expected;
34
+ }
35
+ function acceptable(defect) {
36
+ const expected = EXPECTED[defect];
37
+ return Array.isArray(expected) ? expected : [expected];
38
+ }
39
+ /** Every check id reachable from `id` by following `dependsOn`, transitively. */
40
+ function ancestorsOf(id, seen = new Set()) {
41
+ const check = CHECKS.find((candidate) => candidate.id === id);
42
+ for (const parent of check?.dependsOn ?? []) {
43
+ if (seen.has(parent))
44
+ continue;
45
+ seen.add(parent);
46
+ ancestorsOf(parent, seen);
47
+ }
48
+ return seen;
49
+ }
50
+ export async function runFuzz(options = {}) {
51
+ const { backend = "memory", cases = 25, dialect = "postgrest", maxDefects = 4, seed: rootSeed = 1 } = options;
52
+ const { createMemoryServer, createPostgresServer, createSqliteServer } = await import("../reference/http.js");
53
+ const factory = backend === "memory" ? createMemoryServer : backend === "sqlite" ? createSqliteServer : createPostgresServer;
54
+ /* Defects the chosen backend or dialect cannot express are excluded from the draw rather than
55
+ * excused afterwards — a case that cannot fail teaches nothing and still costs a run. */
56
+ const pool = defectsFor(backend, dialect);
57
+ const results = [];
58
+ const random = rng(rootSeed);
59
+ for (let index = 0; index < cases; index++) {
60
+ const caseSeed = Math.floor(random() * 1_000_000);
61
+ const draw = rng(caseSeed);
62
+ const count = 1 + Math.floor(draw() * maxDefects);
63
+ const injected = [];
64
+ while (injected.length < count) {
65
+ const pick = pool[Math.floor(draw() * pool.length)];
66
+ if (!injected.includes(pick))
67
+ injected.push(pick);
68
+ }
69
+ const result = await runOneCase(factory, injected, caseSeed, dialect);
70
+ results.push(result);
71
+ options.onCase?.(result);
72
+ }
73
+ return results;
74
+ }
75
+ async function runOneCase(factory, injected, seed, dialect) {
76
+ const base = {
77
+ cascaded: [],
78
+ findings: 0,
79
+ unresolved: [],
80
+ injected,
81
+ missed: [],
82
+ ok: false,
83
+ seed,
84
+ spurious: [],
85
+ };
86
+ const server = await factory({ defects: injected, dialect });
87
+ try {
88
+ const result = await run({
89
+ baseUrl: server.url,
90
+ principals: PRINCIPALS,
91
+ seed: 42,
92
+ spec: `${server.url}/v1/openapi/spec`,
93
+ });
94
+ /* Coverage gaps describe what oat could not test, not what the backend got wrong. */
95
+ const real = result.findings.filter((finding) => finding.verdict !== "COVERAGE_GAP");
96
+ const fired = new Set(real.map((finding) => finding.check));
97
+ base.findings = real.length;
98
+ /* Anything the injected set can justify — the primaries plus their documented
99
+ * consequences. A finding outside this union is oat inventing a defect. */
100
+ const justified = new Set(injected.flatMap(acceptable));
101
+ const stated = new Map(result.inconclusive.map((entry) => [entry.check, entry.reason]));
102
+ for (const defect of injected) {
103
+ const want = primary(defect);
104
+ if (fired.has(want))
105
+ continue;
106
+ /* Not fired. Acceptable in exactly two cases: something `want` depends on is itself
107
+ * broken — cascade suppression working — or the check ran and reported *why* it could
108
+ * not conclude. Anything else is oat going quiet, which is the real failure. */
109
+ const broken = [...ancestorsOf(want)].find((ancestor) => fired.has(ancestor));
110
+ if (broken !== undefined) {
111
+ base.cascaded.push({ because: broken, defect });
112
+ continue;
113
+ }
114
+ const reason = stated.get(want);
115
+ if (reason !== undefined) {
116
+ base.unresolved.push({ defect, reason });
117
+ continue;
118
+ }
119
+ base.missed.push({ defect, primary: want });
120
+ }
121
+ for (const finding of real) {
122
+ if (justified.has(finding.check))
123
+ continue;
124
+ base.spurious.push({
125
+ check: finding.check,
126
+ detail: finding.detail,
127
+ entity: finding.entity ?? "",
128
+ summary: finding.summary,
129
+ });
130
+ }
131
+ base.ok = base.missed.length === 0 && base.spurious.length === 0;
132
+ return base;
133
+ }
134
+ catch (error) {
135
+ base.error = error instanceof Error ? error.message : String(error);
136
+ return base;
137
+ }
138
+ finally {
139
+ await server.close();
140
+ }
141
+ }
142
+ export function renderFuzz(results) {
143
+ const lines = [];
144
+ const failed = results.filter((result) => !result.ok);
145
+ lines.push("");
146
+ lines.push(" combination fuzzing — random defect sets, one run each");
147
+ lines.push(" ─────────────────────────────────────────────────────────────────────────");
148
+ for (const result of failed) {
149
+ lines.push(` ✗ seed ${result.seed} [${result.injected.join(" + ")}]`);
150
+ if (result.error !== undefined)
151
+ lines.push(` run failed: ${result.error}`);
152
+ for (const miss of result.missed) {
153
+ lines.push(` missed ${miss.defect} — expected ${miss.primary}, nothing fired`);
154
+ }
155
+ for (const extra of result.spurious) {
156
+ lines.push(` spurious ${extra.check}${extra.entity === "" ? "" : ` (${extra.entity})`}`);
157
+ lines.push(` ${extra.summary}`);
158
+ /* Truncated, not omitted: the evidence is what distinguishes a real regression from a
159
+ * timing artefact, and a rare case may never reproduce on demand. */
160
+ lines.push(` ${extra.detail.replace(/\s+/g, " ").slice(0, 200)}`);
161
+ }
162
+ }
163
+ const cascaded = results.reduce((sum, result) => sum + result.cascaded.length, 0);
164
+ const unresolved = results.reduce((sum, result) => sum + result.unresolved.length, 0);
165
+ lines.push("");
166
+ lines.push(` ${results.length - failed.length}/${results.length} combinations diagnosed correctly` +
167
+ ` · ${cascaded} suppressed as cascades` +
168
+ ` · ${unresolved} reported as inconclusive`);
169
+ lines.push("");
170
+ return { failures: failed.length, text: lines.join("\n") };
171
+ }
172
+ /**
173
+ * Precision under varied data, against a backend with no defects at all.
174
+ *
175
+ * The combination fuzzer varies the *faults*; this varies the *data*. Every check builds its
176
+ * cohort from a seed — empty strings, LIKE metacharacters, unicode, nulls, lexical extremes — and
177
+ * the conformance suite has only ever used seed 42. A property that holds at 42 and fails at 43
178
+ * was never a property of the contract; it was a property of that one fixture.
179
+ *
180
+ * Here the backend is correct by construction, so the bar is absolute: any finding at all is a
181
+ * false positive, and false positives are what make a tool get switched off.
182
+ */
183
+ export async function runPrecision(options = {}) {
184
+ const { backend = "memory", cases = 50, dialect = "postgrest", seed: rootSeed = 1 } = options;
185
+ const { createMemoryServer, createPostgresServer, createSqliteServer } = await import("../reference/http.js");
186
+ const factory = backend === "memory" ? createMemoryServer : backend === "sqlite" ? createSqliteServer : createPostgresServer;
187
+ const results = [];
188
+ const random = rng(rootSeed);
189
+ for (let index = 0; index < cases; index++) {
190
+ const seed = Math.floor(random() * 1_000_000);
191
+ const server = await factory({ defects: [], dialect });
192
+ try {
193
+ const result = await run({
194
+ baseUrl: server.url,
195
+ principals: PRINCIPALS,
196
+ seed,
197
+ spec: `${server.url}/v1/openapi/spec`,
198
+ });
199
+ results.push({
200
+ findings: result.findings
201
+ .filter((finding) => finding.verdict !== "COVERAGE_GAP")
202
+ .map((finding) => ({
203
+ check: finding.check,
204
+ entity: finding.entity ?? "",
205
+ summary: finding.summary,
206
+ })),
207
+ inconclusive: result.inconclusive.length,
208
+ seed,
209
+ });
210
+ }
211
+ catch (error) {
212
+ results.push({
213
+ error: error instanceof Error ? error.message : String(error),
214
+ findings: [],
215
+ inconclusive: 0,
216
+ seed,
217
+ });
218
+ }
219
+ finally {
220
+ await server.close();
221
+ }
222
+ }
223
+ return results;
224
+ }
225
+ export function renderPrecision(results) {
226
+ const lines = [];
227
+ const bad = results.filter((r) => r.findings.length > 0 || r.error !== undefined);
228
+ lines.push("");
229
+ lines.push(" precision stress — correct backend, varied cohort data");
230
+ lines.push(" ─────────────────────────────────────────────────────────────────────────");
231
+ for (const result of bad) {
232
+ lines.push(` ✗ seed ${result.seed}`);
233
+ if (result.error !== undefined)
234
+ lines.push(` run failed: ${result.error}`);
235
+ for (const finding of result.findings) {
236
+ lines.push(` false positive ${finding.check} (${finding.entity}) — ${finding.summary}`);
237
+ }
238
+ }
239
+ const unresolved = results.reduce((sum, r) => sum + r.inconclusive, 0);
240
+ lines.push("");
241
+ lines.push(` ${results.length - bad.length}/${results.length} cohorts produced no false positives` +
242
+ ` · ${unresolved} check(s) reported as inconclusive`);
243
+ lines.push("");
244
+ return { failures: bad.length, text: lines.join("\n") };
245
+ }
246
+ //# sourceMappingURL=fuzz.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fuzz.js","sourceRoot":"","sources":["../../src/conformance/fuzz.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * What a run left behind, read from the backend itself rather than from oat's own bookkeeping.
3
+ *
4
+ * Counting `created − removed` trusts the ledger it is meant to audit: a record oat never ledgered
5
+ * is neither created nor removed, and the count reads zero while tables sit in the backend. Every
6
+ * live record present after the run and absent before it was left behind, whoever made it.
7
+ */
8
+ export type StoreSnapshot = Record<string, Array<Record<string, unknown>>>;
9
+ export declare function leftBehind(before: StoreSnapshot, after: StoreSnapshot): string[];
10
+ //# sourceMappingURL=leaks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaks.d.ts","sourceRoot":"","sources":["../../src/conformance/leaks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAA;AAE1E,wBAAgB,UAAU,CAAC,MAAM,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE,CAYhF"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * What a run left behind, read from the backend itself rather than from oat's own bookkeeping.
3
+ *
4
+ * Counting `created − removed` trusts the ledger it is meant to audit: a record oat never ledgered
5
+ * is neither created nor removed, and the count reads zero while tables sit in the backend. Every
6
+ * live record present after the run and absent before it was left behind, whoever made it.
7
+ */
8
+ export function leftBehind(before, after) {
9
+ const out = [];
10
+ for (const [entity, rows] of Object.entries(after)) {
11
+ const existed = new Set((before[entity] ?? []).map((row) => JSON.stringify(row.id)));
12
+ for (const row of rows) {
13
+ if (existed.has(JSON.stringify(row.id)))
14
+ continue;
15
+ /* A tombstone is a removal: the API no longer serves it. */
16
+ if (row.deleted_at !== null && row.deleted_at !== undefined)
17
+ continue;
18
+ out.push(`${entity} ${String(row.id)}`);
19
+ }
20
+ }
21
+ return out;
22
+ }
23
+ //# sourceMappingURL=leaks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"leaks.js","sourceRoot":"","sources":["../../src/conformance/leaks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,MAAM,UAAU,UAAU,CAAC,MAAqB,EAAE,KAAoB;IACrE,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,KAAK,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACpD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAA;QACpF,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACxB,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBAAE,SAAQ;YACjD,4DAA4D;YAC5D,IAAI,GAAG,CAAC,UAAU,KAAK,IAAI,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS;gBAAE,SAAQ;YACrE,GAAG,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC,CAAA;QACxC,CAAC;IACF,CAAC;IACD,OAAO,GAAG,CAAA;AACX,CAAC"}
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Conformance cases on worker processes.
3
+ *
4
+ * Every case already owns its server, so cases share nothing but the CPU — and the suite is
5
+ * CPU-bound: oat and the reference backend run in one process, so concurrency inside it buys
6
+ * nothing. Separate processes do, each with its own heap and event loop. A task is a slice of a leg — a pass's baselines or a chunk of its defects,
7
+ * the shape suite, or the recall cases behind one shape — and comes back as plain data the parent
8
+ * assembles and prints in order.
9
+ */
10
+ import type { ShapeCase } from "./shapes.ts";
11
+ import type { DefectName } from "../reference/defects.ts";
12
+ import type { Backend, CaseResult, ParserResult } from "./suite.ts";
13
+ export type ConformanceTask = {
14
+ kind: "baselines";
15
+ backend: Backend;
16
+ dialect: string;
17
+ } | {
18
+ kind: "defects";
19
+ backend: Backend;
20
+ dialect: string;
21
+ defects: DefectName[];
22
+ } | {
23
+ kind: "shapes";
24
+ } | {
25
+ kind: "recall";
26
+ shapes: ShapeCase[];
27
+ } | {
28
+ kind: "scope";
29
+ defects: string[];
30
+ known: Record<string, string[]>;
31
+ };
32
+ export type ConformanceAnswer = {
33
+ kind: "cases";
34
+ cases: ShapeCase[];
35
+ } | {
36
+ kind: "leg";
37
+ results: CaseResult[];
38
+ } | {
39
+ kind: "results";
40
+ results: ParserResult[];
41
+ };
42
+ export interface ConformancePool {
43
+ run(task: ConformanceTask): Promise<ConformanceAnswer>;
44
+ close(): Promise<void>;
45
+ }
46
+ /** Threads used when `--jobs` is not given: most of the machine, never more than four. */
47
+ export declare function defaultJobs(): number;
48
+ export declare function createPool(jobs: number): ConformancePool;
49
+ //# sourceMappingURL=pool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.d.ts","sourceRoot":"","sources":["../../src/conformance/pool.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAEnE,MAAM,MAAM,eAAe,GAGxB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACxD;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,GAC7E;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,SAAS,EAAE,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAA;CAAE,CAAA;AAExE,MAAM,MAAM,iBAAiB,GAC1B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,SAAS,EAAE,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,UAAU,EAAE,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,YAAY,EAAE,CAAA;CAAE,CAAA;AAE/C,MAAM,WAAW,eAAe;IAC/B,GAAG,CAAC,IAAI,EAAE,eAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAAA;IACtD,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CACtB;AAED,0FAA0F;AAC1F,wBAAgB,WAAW,IAAI,MAAM,CAEpC;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,eAAe,CAmExD"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Conformance cases on worker processes.
3
+ *
4
+ * Every case already owns its server, so cases share nothing but the CPU — and the suite is
5
+ * CPU-bound: oat and the reference backend run in one process, so concurrency inside it buys
6
+ * nothing. Separate processes do, each with its own heap and event loop. A task is a slice of a leg — a pass's baselines or a chunk of its defects,
7
+ * the shape suite, or the recall cases behind one shape — and comes back as plain data the parent
8
+ * assembles and prints in order.
9
+ */
10
+ import { availableParallelism } from "node:os";
11
+ import { fork } from "node:child_process";
12
+ /** Threads used when `--jobs` is not given: most of the machine, never more than four. */
13
+ export function defaultJobs() {
14
+ return Math.max(1, Math.min(4, availableParallelism() - 1));
15
+ }
16
+ export function createPool(jobs) {
17
+ const script = new URL("./worker.js", import.meta.url);
18
+ const idle = [];
19
+ const all = [];
20
+ const queue = [];
21
+ const next = (worker) => {
22
+ const job = queue.shift();
23
+ if (job === undefined) {
24
+ idle.push(worker);
25
+ return;
26
+ }
27
+ const settle = (message) => {
28
+ worker.off("error", fail);
29
+ worker.off("exit", died);
30
+ const reply = message;
31
+ if (reply.ok && reply.answer !== undefined)
32
+ job.resolve(reply.answer);
33
+ else
34
+ job.reject(new Error(reply.error ?? "conformance worker failed"));
35
+ next(worker);
36
+ };
37
+ const fail = (error) => {
38
+ worker.off("message", settle);
39
+ worker.off("exit", died);
40
+ job.reject(error);
41
+ };
42
+ const died = (code, signal) => {
43
+ worker.off("message", settle);
44
+ worker.off("error", fail);
45
+ job.reject(new Error(`conformance worker exited (${signal ?? code}) during a task`));
46
+ };
47
+ worker.once("message", settle);
48
+ worker.once("error", fail);
49
+ worker.once("exit", died);
50
+ worker.send(job.task);
51
+ };
52
+ for (let index = 0; index < Math.max(1, jobs); index++) {
53
+ /* Structured clone, as between threads: results carry Maps and Sets. */
54
+ const worker = fork(script, { serialization: "advanced", stdio: ["ignore", "inherit", "inherit", "ipc"] });
55
+ all.push(worker);
56
+ idle.push(worker);
57
+ }
58
+ return {
59
+ close: async () => {
60
+ await Promise.all(all.map((worker) => new Promise((resolve) => {
61
+ if (worker.exitCode !== null || worker.signalCode !== null)
62
+ return resolve();
63
+ worker.once("exit", () => resolve());
64
+ worker.kill();
65
+ })));
66
+ },
67
+ run: (task) => new Promise((resolve, reject) => {
68
+ queue.push({ reject, resolve, task });
69
+ const worker = idle.shift();
70
+ if (worker !== undefined)
71
+ next(worker);
72
+ }),
73
+ };
74
+ }
75
+ //# sourceMappingURL=pool.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pool.js","sourceRoot":"","sources":["../../src/conformance/pool.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Reactive 429 backoff and plan-limit adopt. Tags stay the proactive path; these cases prove
3
+ * the first 429 is not a seed failure and that a 402 does not invent a table.
4
+ */
5
+ import type { ParserResult } from "./suite.ts";
6
+ export declare function runRateLimitSuite(): Promise<ParserResult[]>;
7
+ //# sourceMappingURL=rate-limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit.d.ts","sourceRoot":"","sources":["../../src/conformance/rate-limit.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAuH9C,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAuRjE"}