@kirrosh/zond 0.22.0 → 0.26.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 (282) hide show
  1. package/CHANGELOG.md +811 -0
  2. package/README.md +59 -6
  3. package/package.json +9 -7
  4. package/src/CLAUDE.md +112 -0
  5. package/src/cli/argv.ts +122 -0
  6. package/src/cli/commands/add-api.ts +146 -0
  7. package/src/cli/commands/api/annotate/idempotency.ts +59 -0
  8. package/src/cli/commands/api/annotate/index.ts +880 -0
  9. package/src/cli/commands/api/annotate/lifecycle.ts +74 -0
  10. package/src/cli/commands/api/annotate/overlay.ts +206 -0
  11. package/src/cli/commands/api/annotate/pagination.ts +64 -0
  12. package/src/cli/commands/api/annotate/prompts.ts +220 -0
  13. package/src/cli/commands/api/annotate/readback.ts +58 -0
  14. package/src/cli/commands/api/annotate/resources.ts +91 -0
  15. package/src/cli/commands/api/annotate/seed-bodies.ts +61 -0
  16. package/src/cli/commands/audit.ts +786 -0
  17. package/src/cli/commands/catalog.ts +35 -0
  18. package/src/cli/commands/check.ts +361 -0
  19. package/src/cli/commands/checks.ts +1072 -0
  20. package/src/cli/commands/ci-init.ts +43 -0
  21. package/src/cli/commands/clean.ts +212 -0
  22. package/src/cli/commands/cleanup.ts +236 -0
  23. package/src/cli/commands/completions.ts +16 -0
  24. package/src/cli/commands/coverage.ts +823 -132
  25. package/src/cli/commands/db.ts +486 -12
  26. package/src/cli/commands/describe.ts +37 -2
  27. package/src/cli/commands/discover.ts +1356 -0
  28. package/src/cli/commands/doctor.ts +661 -0
  29. package/src/cli/commands/fixtures.ts +402 -0
  30. package/src/cli/commands/generate.ts +438 -47
  31. package/src/cli/commands/init/bootstrap.ts +34 -2
  32. package/src/cli/commands/{init.ts → init/index.ts} +99 -5
  33. package/src/cli/commands/init/skills.ts +99 -3
  34. package/src/cli/commands/init/templates/agents.md +77 -64
  35. package/src/cli/commands/init/templates/skills/warm-up-target.md +122 -0
  36. package/src/cli/commands/init/templates/skills/zond-checks.md +621 -0
  37. package/src/cli/commands/init/templates/skills/zond-seed.md +114 -0
  38. package/src/cli/commands/init/templates/skills/zond-triage.md +272 -0
  39. package/src/cli/commands/init/templates/skills/zond.md +802 -125
  40. package/src/cli/commands/init/templates/zond-config.yml +8 -9
  41. package/src/cli/commands/prepare-fixtures.ts +97 -0
  42. package/src/cli/commands/probe/_seed-bodies.ts +52 -0
  43. package/src/cli/commands/probe/mass-assignment.ts +594 -0
  44. package/src/cli/commands/probe/security.ts +537 -0
  45. package/src/cli/commands/probe/static.ts +255 -0
  46. package/src/cli/commands/probe/webhooks.ts +163 -0
  47. package/src/cli/commands/probe.ts +535 -0
  48. package/src/cli/commands/reference.ts +87 -0
  49. package/src/cli/commands/refresh-api.ts +227 -0
  50. package/src/cli/commands/remove-api.ts +150 -0
  51. package/src/cli/commands/report-bundle.ts +310 -0
  52. package/src/cli/commands/report.ts +241 -0
  53. package/src/cli/commands/request.ts +495 -4
  54. package/src/cli/commands/run.ts +870 -53
  55. package/src/cli/commands/schema-from-runs.ts +128 -0
  56. package/src/cli/commands/secrets.ts +133 -0
  57. package/src/cli/commands/session.ts +244 -0
  58. package/src/cli/commands/use.ts +18 -1
  59. package/src/cli/index.ts +20 -3
  60. package/src/cli/json-envelope.ts +92 -3
  61. package/src/cli/json-schemas.ts +314 -0
  62. package/src/cli/output.ts +17 -1
  63. package/src/cli/program.ts +199 -635
  64. package/src/cli/resolve.ts +105 -0
  65. package/src/cli/safe-live.ts +24 -0
  66. package/src/cli/status-filter.ts +114 -0
  67. package/src/cli/util/api-context.ts +85 -0
  68. package/src/cli/version.ts +5 -0
  69. package/src/core/audit/persist.ts +183 -0
  70. package/src/core/checks/budget.ts +59 -0
  71. package/src/core/checks/checks/_crud-helpers.ts +133 -0
  72. package/src/core/checks/checks/_negative_mutator.ts +133 -0
  73. package/src/core/checks/checks/_readback-helpers.ts +133 -0
  74. package/src/core/checks/checks/content_type_conformance.ts +39 -0
  75. package/src/core/checks/checks/cross_call_references.ts +147 -0
  76. package/src/core/checks/checks/cursor_boundary_fuzzing.ts +219 -0
  77. package/src/core/checks/checks/ensure_resource_availability.ts +62 -0
  78. package/src/core/checks/checks/idempotency_replay.ts +242 -0
  79. package/src/core/checks/checks/ignored_auth.ts +254 -0
  80. package/src/core/checks/checks/index.ts +68 -0
  81. package/src/core/checks/checks/lifecycle_transitions.ts +416 -0
  82. package/src/core/checks/checks/missing_required_header.ts +40 -0
  83. package/src/core/checks/checks/negative_data_rejection.ts +148 -0
  84. package/src/core/checks/checks/not_a_server_error.ts +35 -0
  85. package/src/core/checks/checks/open_cors_on_sensitive.ts +160 -0
  86. package/src/core/checks/checks/pagination_invariants.ts +419 -0
  87. package/src/core/checks/checks/positive_data_acceptance.ts +33 -0
  88. package/src/core/checks/checks/rate_limit_headers_absent.ts +77 -0
  89. package/src/core/checks/checks/response_headers_conformance.ts +74 -0
  90. package/src/core/checks/checks/response_schema_conformance.ts +30 -0
  91. package/src/core/checks/checks/status_code_conformance.ts +132 -0
  92. package/src/core/checks/checks/unsupported_method.ts +63 -0
  93. package/src/core/checks/checks/use_after_free.ts +78 -0
  94. package/src/core/checks/index.ts +30 -0
  95. package/src/core/checks/mode.ts +82 -0
  96. package/src/core/checks/recommended-action.ts +68 -0
  97. package/src/core/checks/registry.ts +78 -0
  98. package/src/core/checks/runner.ts +1461 -0
  99. package/src/core/checks/sarif.ts +230 -0
  100. package/src/core/checks/spec-findings.ts +308 -0
  101. package/src/core/checks/stateful.ts +121 -0
  102. package/src/core/checks/types.ts +305 -0
  103. package/src/core/checks/zond-extensions.ts +73 -0
  104. package/src/core/classifier/recommended-action.ts +251 -0
  105. package/src/core/context/current.ts +22 -6
  106. package/src/core/context/session.ts +78 -0
  107. package/src/core/coverage/loader.ts +216 -0
  108. package/src/core/coverage/reasons.ts +300 -0
  109. package/src/core/diagnostics/db-analysis.ts +293 -59
  110. package/src/core/diagnostics/failure-class.ts +140 -0
  111. package/src/core/diagnostics/failure-hints.ts +88 -89
  112. package/src/core/diagnostics/spec-pointer.ts +99 -0
  113. package/src/core/diagnostics/suggested-fixes.ts +155 -0
  114. package/src/core/exporter/case-study/index.ts +270 -0
  115. package/src/core/exporter/curl.ts +40 -0
  116. package/src/core/exporter/exporter.ts +48 -0
  117. package/src/core/exporter/html-report/escape.ts +24 -0
  118. package/src/core/exporter/html-report/index.ts +479 -0
  119. package/src/core/exporter/html-report/script.ts +100 -0
  120. package/src/core/exporter/html-report/styles.ts +408 -0
  121. package/src/core/generator/chunker.ts +38 -19
  122. package/src/core/generator/coverage-phase.ts +0 -0
  123. package/src/core/generator/data-factory.ts +586 -22
  124. package/src/core/generator/describe.ts +1 -1
  125. package/src/core/generator/fixtures-builder.ts +332 -0
  126. package/src/core/generator/index.ts +5 -5
  127. package/src/core/generator/openapi-reader.ts +135 -7
  128. package/src/core/generator/path-param-disambig.ts +140 -0
  129. package/src/core/generator/resources-builder.ts +898 -0
  130. package/src/core/generator/schema-utils.ts +33 -3
  131. package/src/core/generator/serializer.ts +103 -13
  132. package/src/core/generator/suite-generator.ts +583 -122
  133. package/src/core/generator/types.ts +14 -0
  134. package/src/core/identity/identity-file.ts +0 -0
  135. package/src/core/lint/affects.ts +28 -0
  136. package/src/core/lint/config.ts +96 -0
  137. package/src/core/lint/format.ts +42 -0
  138. package/src/core/lint/index.ts +94 -0
  139. package/src/core/lint/reporter.ts +128 -0
  140. package/src/core/lint/rules/consistency.ts +158 -0
  141. package/src/core/lint/rules/heuristics.ts +97 -0
  142. package/src/core/lint/rules/strictness.ts +109 -0
  143. package/src/core/lint/types.ts +96 -0
  144. package/src/core/lint/walker.ts +248 -0
  145. package/src/core/meta/meta-store.ts +6 -73
  146. package/src/core/output/README.md +73 -0
  147. package/src/core/output/index.ts +13 -0
  148. package/src/core/output/run.ts +91 -0
  149. package/src/core/output/types.ts +122 -0
  150. package/src/core/parser/dynamic-values.ts +160 -0
  151. package/src/core/parser/env-interpolation.ts +104 -0
  152. package/src/core/parser/filter.ts +57 -0
  153. package/src/core/parser/schema.ts +129 -4
  154. package/src/core/parser/types.ts +19 -1
  155. package/src/core/parser/variables.ts +0 -0
  156. package/src/core/parser/yaml-parser.ts +58 -12
  157. package/src/core/probe/bootstrap.ts +34 -0
  158. package/src/core/probe/dry-run-envelope.ts +61 -0
  159. package/src/core/probe/mass-assignment/classify.ts +175 -0
  160. package/src/core/probe/mass-assignment/cleanup.ts +52 -0
  161. package/src/core/probe/mass-assignment/digest.ts +114 -0
  162. package/src/core/probe/mass-assignment/orchestrator.ts +459 -0
  163. package/src/core/probe/mass-assignment/regression.ts +141 -0
  164. package/src/core/probe/mass-assignment/suspects.ts +92 -0
  165. package/src/core/probe/mass-assignment/types.ts +135 -0
  166. package/src/core/probe/mass-assignment-probe-class.ts +198 -0
  167. package/src/core/probe/mass-assignment-probe.ts +27 -0
  168. package/src/core/probe/mass-assignment-template.ts +240 -0
  169. package/src/core/probe/method-probe.ts +43 -76
  170. package/src/core/probe/method-shared.ts +69 -0
  171. package/src/core/probe/negative-probe.ts +183 -149
  172. package/src/core/probe/orphan-tracker.ts +188 -0
  173. package/src/core/probe/path-discovery.ts +439 -0
  174. package/src/core/probe/probe-harness.ts +119 -0
  175. package/src/core/probe/registry.ts +89 -0
  176. package/src/core/probe/runner.ts +136 -0
  177. package/src/core/probe/security/baseline.ts +174 -0
  178. package/src/core/probe/security/classify.ts +341 -0
  179. package/src/core/probe/security/cleanup.ts +125 -0
  180. package/src/core/probe/security/detectors.ts +71 -0
  181. package/src/core/probe/security/digest.ts +104 -0
  182. package/src/core/probe/security/orchestrator.ts +398 -0
  183. package/src/core/probe/security/regression.ts +103 -0
  184. package/src/core/probe/security/types.ts +151 -0
  185. package/src/core/probe/security-probe-class.ts +207 -0
  186. package/src/core/probe/security-probe.ts +32 -0
  187. package/src/core/probe/shared.ts +531 -0
  188. package/src/core/probe/static-probe-class.ts +125 -0
  189. package/src/core/probe/types.ts +165 -0
  190. package/src/core/probe/verdict-aggregator.ts +33 -0
  191. package/src/core/probe/webhooks-probe.ts +282 -0
  192. package/src/core/reporter/console.ts +41 -2
  193. package/src/core/reporter/index.ts +2 -3
  194. package/src/core/reporter/json.ts +11 -1
  195. package/src/core/reporter/junit.ts +27 -12
  196. package/src/core/reporter/ndjson.ts +37 -0
  197. package/src/core/reporter/types.ts +3 -0
  198. package/src/core/runner/assertions.ts +59 -2
  199. package/src/core/runner/async-pool.ts +108 -0
  200. package/src/core/runner/auth-path.ts +8 -0
  201. package/src/core/runner/ci-context.ts +72 -0
  202. package/src/core/runner/executor.ts +265 -36
  203. package/src/core/runner/form-encode.ts +41 -0
  204. package/src/core/runner/http-client.ts +112 -2
  205. package/src/core/runner/learn-drift.ts +293 -0
  206. package/src/core/runner/preflight-vars.ts +153 -0
  207. package/src/core/runner/progress-tracker.ts +73 -0
  208. package/src/core/runner/rate-limiter.ts +87 -33
  209. package/src/core/runner/run-kind.ts +45 -0
  210. package/src/core/runner/schema-validator.ts +308 -0
  211. package/src/core/runner/send-request.ts +158 -20
  212. package/src/core/runner/types.ts +44 -0
  213. package/src/core/secrets/registry.ts +164 -0
  214. package/src/core/secrets/secrets-file.ts +115 -0
  215. package/src/core/selectors/operation-filter.ts +144 -0
  216. package/src/core/setup-api.ts +457 -20
  217. package/src/core/severity/category.ts +94 -0
  218. package/src/core/severity/index.ts +58 -0
  219. package/src/core/spec/infer-schema.ts +102 -0
  220. package/src/core/spec/layers.ts +154 -0
  221. package/src/core/spec/merge-specs.ts +156 -0
  222. package/src/core/spec/schema-from-runs.ts +117 -0
  223. package/src/core/spec/schema-overlay.ts +130 -0
  224. package/src/core/util/ajv.ts +13 -0
  225. package/src/core/util/format-eta.ts +21 -0
  226. package/src/core/util/headers.ts +9 -0
  227. package/src/core/util/url.ts +24 -0
  228. package/src/core/utils.ts +5 -1
  229. package/src/core/workspace/config.ts +129 -0
  230. package/src/core/workspace/fixture-gap-report.ts +84 -0
  231. package/src/core/workspace/fixture-gaps.ts +71 -0
  232. package/src/core/workspace/manifest.ts +283 -0
  233. package/src/core/workspace/output-rotation.ts +62 -0
  234. package/src/core/workspace/root.ts +13 -11
  235. package/src/core/workspace/triage-path.ts +87 -0
  236. package/src/db/lint-runs.ts +47 -0
  237. package/src/db/migrate.ts +128 -0
  238. package/src/db/migrations/0001_run_kind.sql +25 -0
  239. package/src/db/migrations/0002_run_kind_request.sql +59 -0
  240. package/src/db/migrations/sql.d.ts +4 -0
  241. package/src/db/queries/collections.ts +133 -0
  242. package/src/db/queries/coverage.ts +9 -0
  243. package/src/db/queries/dashboard.ts +59 -0
  244. package/src/db/queries/results.ts +216 -0
  245. package/src/db/queries/runs.ts +289 -0
  246. package/src/db/queries/sessions.ts +42 -0
  247. package/src/db/queries/settings.ts +28 -0
  248. package/src/db/queries/types.ts +172 -0
  249. package/src/db/queries.ts +75 -802
  250. package/src/db/schema.ts +178 -50
  251. package/src/cli/commands/export.ts +0 -144
  252. package/src/cli/commands/guide.ts +0 -127
  253. package/src/cli/commands/init/templates/skills/scenarios.md +0 -97
  254. package/src/cli/commands/probe-methods.ts +0 -108
  255. package/src/cli/commands/probe-validation.ts +0 -124
  256. package/src/cli/commands/serve.ts +0 -114
  257. package/src/cli/commands/sync.ts +0 -268
  258. package/src/cli/commands/update.ts +0 -189
  259. package/src/cli/commands/validate.ts +0 -34
  260. package/src/core/diagnostics/render-md.ts +0 -112
  261. package/src/core/exporter/postman.ts +0 -963
  262. package/src/core/generator/guide-builder.ts +0 -253
  263. package/src/core/meta/types.ts +0 -19
  264. package/src/core/parser/index.ts +0 -21
  265. package/src/core/runner/execute-run.ts +0 -132
  266. package/src/core/runner/index.ts +0 -12
  267. package/src/core/sync/spec-differ.ts +0 -38
  268. package/src/web/data/collection-state.ts +0 -362
  269. package/src/web/routes/api.ts +0 -314
  270. package/src/web/routes/dashboard.ts +0 -350
  271. package/src/web/routes/runs.ts +0 -64
  272. package/src/web/schemas.ts +0 -121
  273. package/src/web/server.ts +0 -134
  274. package/src/web/static/htmx.min.cjs +0 -1
  275. package/src/web/static/style.css +0 -1148
  276. package/src/web/views/endpoints-tab.ts +0 -174
  277. package/src/web/views/explorer-tab.ts +0 -402
  278. package/src/web/views/health-strip.ts +0 -92
  279. package/src/web/views/layout.ts +0 -48
  280. package/src/web/views/results.ts +0 -210
  281. package/src/web/views/runs-tab.ts +0 -126
  282. package/src/web/views/suites-tab.ts +0 -181
@@ -0,0 +1,314 @@
1
+ /**
2
+ * TASK-295: zod sources of truth for the `--json` envelope shape and its
3
+ * sub-types. Run `bun run scripts/emit-json-schemas.ts` after changing
4
+ * any of these to regenerate `docs/json-schema/*.schema.json`.
5
+ *
6
+ * Why zod first, JSON Schema second: zod is the type AND the validator
7
+ * we already ship; emitting JSON Schema from it keeps the published
8
+ * schema and the runtime checks in lock-step. New fields land here and
9
+ * propagate, instead of drifting between two hand-maintained shapes.
10
+ */
11
+
12
+ import { z } from "zod";
13
+
14
+ /** TASK-296 closed enum — must stay in sync with `ZondErrorCode` in
15
+ * `src/cli/json-envelope.ts`. */
16
+ export const ZondErrorCodeSchema = z.enum([
17
+ "unknown_error",
18
+ "env_missing",
19
+ "fixture_missing",
20
+ "network_timeout",
21
+ "network_error",
22
+ "sandbox_blocked",
23
+ "spec_load_failure",
24
+ "yaml_parse_error",
25
+ "workspace_not_found",
26
+ "file_not_found",
27
+ "permission_denied",
28
+ "argument_invalid",
29
+ "api_not_registered",
30
+ "db_error",
31
+ "auth_config_error",
32
+ ]);
33
+
34
+ export const ZondErrorSchema = z.object({
35
+ code: ZondErrorCodeSchema,
36
+ message: z.string(),
37
+ details: z.record(z.string(), z.unknown()).optional(),
38
+ });
39
+
40
+ /** TASK-294 closed enum — must stay in sync with `RecommendedAction` in
41
+ * `src/core/diagnostics/failure-hints.ts` and the per-check mapping in
42
+ * `src/core/checks/recommended-action.ts` (ARV-11).
43
+ * ARV-11 added three values for the depth-checks framework:
44
+ * - `tighten_validation` — server accepted invalid input.
45
+ * - `add_required_header` — server didn't enforce a required header.
46
+ * - `wontfix_known_limitation` — known/accepted gap; agent should
47
+ * not retry or report. */
48
+ export const RecommendedActionSchema = z.enum([
49
+ "report_backend_bug",
50
+ "fix_auth_config",
51
+ "fix_test_logic",
52
+ "fix_network_config",
53
+ "fix_env",
54
+ "fix_spec",
55
+ "fix_fixture",
56
+ // ARV-42 — re-run `zond generate` for failures rooted in generator-emitted
57
+ // bodies; editing the YAML directly is overwritten by the next regenerate.
58
+ "regenerate_suite",
59
+ "tighten_validation",
60
+ "add_required_header",
61
+ "wontfix_known_limitation",
62
+ ]);
63
+
64
+ /** Envelope body. `data` is open (`unknown`) so this schema covers every
65
+ * command without enumerating each payload — command-specific schemas
66
+ * can refine `data` per-command in a follow-up. */
67
+ export const JsonEnvelopeSchema = z.object({
68
+ ok: z.boolean(),
69
+ command: z.string(),
70
+ data: z.unknown(),
71
+ warnings: z.array(z.string()),
72
+ errors: z.array(ZondErrorSchema),
73
+ exit_code: z.number().int().optional(),
74
+ });
75
+
76
+ /** ARV-1 (m-15): shape of `data` for `zond checks run --json`. The
77
+ * envelope itself stays the generic JsonEnvelopeSchema; this schema
78
+ * pins the per-command payload so agents can validate findings without
79
+ * parsing them by-hand. ARV-11 adds `recommended_action` as a closed
80
+ * enum on each finding. */
81
+ export const SeveritySchema = z.enum(["critical", "high", "medium", "low", "info"]);
82
+ export const CategorySchema = z.enum(["security", "reliability", "contract", "hygiene"]);
83
+
84
+ export const CheckFindingSchema = z.object({
85
+ check: z.string(),
86
+ severity: SeveritySchema,
87
+ // ARV-251: category drives per-section roll-up. Optional on the wire
88
+ // for backwards compat with older NDJSON streams — derived by reader
89
+ // from check id if absent.
90
+ category: CategorySchema.optional(),
91
+ operation: z.object({
92
+ path: z.string(),
93
+ method: z.string(),
94
+ operationId: z.string().optional(),
95
+ }),
96
+ request_signature: z.string(),
97
+ response_summary: z.object({
98
+ status: z.number().int(),
99
+ content_type: z.string().optional(),
100
+ }),
101
+ message: z.string(),
102
+ evidence: z.record(z.string(), z.unknown()).optional(),
103
+ // ARV-11: recommended_action is now a closed enum so agents can
104
+ // route on it without parsing free-form strings. Same enum used by
105
+ // `db diagnose` (TASK-294) plus three depth-check additions.
106
+ recommended_action: RecommendedActionSchema.optional(),
107
+ });
108
+
109
+ export const CheckRunSummarySchema = z.object({
110
+ operations: z.number().int().nonnegative(),
111
+ cases: z.number().int().nonnegative(),
112
+ checks_run: z.number().int().nonnegative(),
113
+ findings: z.number().int().nonnegative(),
114
+ by_severity: z.object({
115
+ critical: z.number().int().nonnegative(),
116
+ high: z.number().int().nonnegative(),
117
+ medium: z.number().int().nonnegative(),
118
+ low: z.number().int().nonnegative(),
119
+ info: z.number().int().nonnegative(),
120
+ }),
121
+ by_category: z.object({
122
+ security: z.number().int().nonnegative(),
123
+ reliability: z.number().int().nonnegative(),
124
+ contract: z.number().int().nonnegative(),
125
+ hygiene: z.number().int().nonnegative(),
126
+ }),
127
+ // ARV-26: per-(check, reason) skip tally — surfaces probe outcomes that
128
+ // never produced a checkable response (e.g. probe got 4xx, schema only on
129
+ // 200) so "0 findings" doesn't read as "all green".
130
+ skipped_outcomes: z.record(z.string(), z.number().int().nonnegative()),
131
+ // ARV-83: structured counterpart to skipped_outcomes — split into
132
+ // {check, reason, count} so consumers don't have to colon-tokenise a
133
+ // reason that may itself contain colons. Sorted by count desc.
134
+ skipped_outcomes_grouped: z.array(z.object({
135
+ check: z.string(),
136
+ reason: z.string(),
137
+ count: z.number().int().nonnegative(),
138
+ })),
139
+ // ARV-283 / ARV-68: count of findings the severity matrix demoted to
140
+ // `info-suppressed`. Excluded from `findings` / `by_severity` so CI
141
+ // gates ignore them, but exposed here so consumers (ajv validators
142
+ // included) accept the field — the runner emits it unconditionally.
143
+ suppressed: z.number().int().nonnegative().optional(),
144
+ });
145
+
146
+ /** ARV-60: spec-level rollup row. Emitted when ≥80% of a check's
147
+ * applicable operations share the same root cause (status drift,
148
+ * missing-declaration skip cluster, or no-detector zero-case). Lives in
149
+ * `data.spec_findings` and as its own `spec_finding` NDJSON event. */
150
+ export const SpecFindingSchema = z.object({
151
+ check: z.string(),
152
+ kind: z.enum(["status_drift", "missing_declaration", "no_detector", "broken_baseline", "other"]),
153
+ severity: SeveritySchema,
154
+ category: CategorySchema.optional(),
155
+ reason: z.string(),
156
+ fix_hint: z.string(),
157
+ affected_operations: z.array(z.object({
158
+ path: z.string(),
159
+ method: z.string(),
160
+ operationId: z.string().optional(),
161
+ })),
162
+ count: z.number().int().nonnegative(),
163
+ applicable: z.number().int().nonnegative(),
164
+ });
165
+
166
+ export const ChecksRunDataSchema = z.object({
167
+ findings: z.array(CheckFindingSchema),
168
+ summary: CheckRunSummarySchema,
169
+ // ARV-60: always present (empty array when no clusters cross 80%).
170
+ spec_findings: z.array(SpecFindingSchema),
171
+ });
172
+
173
+ /** ARV-10 (m-15): NDJSON streaming events emitted by `zond checks run
174
+ * --ndjson`. Each event is a snapshot JSON line on stdout — agents pipe
175
+ * the stream into `jq` / a validator and consume findings as they happen
176
+ * rather than waiting for the run to finish. The discriminated union
177
+ * below is the schema we publish — every emitted line MUST match one
178
+ * branch exactly (verified by ajv in tests). */
179
+ const OperationRefSchema = z.object({
180
+ path: z.string(),
181
+ method: z.string(),
182
+ operationId: z.string().optional(),
183
+ });
184
+
185
+ export const NdjsonCheckStartEventSchema = z.object({
186
+ type: z.literal("check_start"),
187
+ ts: z.string(),
188
+ operation: OperationRefSchema,
189
+ });
190
+
191
+ export const NdjsonCheckResultEventSchema = z.object({
192
+ type: z.literal("check_result"),
193
+ ts: z.string(),
194
+ check: z.string(),
195
+ // ARV-215: severity from the registry (mirrors `zond checks list`
196
+ // [high|medium|low]). Lets consumers group NDJSON by severity without
197
+ // re-joining against the registry.
198
+ severity: z.enum(["info", "low", "medium", "high", "critical"]),
199
+ verdict: z.enum(["pass", "fail"]),
200
+ operation: OperationRefSchema,
201
+ request_signature: z.string(),
202
+ response: z.object({
203
+ status: z.number().int(),
204
+ content_type: z.string().optional(),
205
+ }),
206
+ });
207
+
208
+ export const NdjsonFindingEventSchema = z.object({
209
+ type: z.literal("finding"),
210
+ ts: z.string(),
211
+ // ARV-156: mirror the top-level `check` field carried by check_start /
212
+ // check_result so consumer pipelines can `jq -c '.check'` uniformly
213
+ // across event types without branching on `.type`. The same value lives
214
+ // inside `.finding.check` — existing consumers reading the nested form
215
+ // keep working (back-compat addition, not a rename).
216
+ check: z.string(),
217
+ finding: CheckFindingSchema,
218
+ });
219
+
220
+ export const NdjsonSummaryEventSchema = z.object({
221
+ type: z.literal("summary"),
222
+ ts: z.string(),
223
+ summary: CheckRunSummarySchema,
224
+ });
225
+
226
+ /** ARV-60: rolled-up spec-level finding event. Emitted before the
227
+ * terminal `summary` event so streaming consumers see clusters in the
228
+ * same order the CLI renders them. Per-op `finding` events are NOT
229
+ * removed — both layers coexist. */
230
+ export const NdjsonSpecFindingEventSchema = z.object({
231
+ type: z.literal("spec_finding"),
232
+ ts: z.string(),
233
+ check: z.string(),
234
+ spec_finding: SpecFindingSchema,
235
+ });
236
+
237
+ export const NdjsonEventSchema = z.discriminatedUnion("type", [
238
+ NdjsonCheckStartEventSchema,
239
+ NdjsonCheckResultEventSchema,
240
+ NdjsonFindingEventSchema,
241
+ NdjsonSpecFindingEventSchema,
242
+ NdjsonSummaryEventSchema,
243
+ ]);
244
+
245
+ /** m-17 / ARV-50: shape of `data` for `zond probe <class> --dry-run --json`.
246
+ * Severity is intentionally absent — nothing is classified yet, so
247
+ * reusing the run-time bucket would mislead CI gates (F1-15). The
248
+ * `skip_reason` enum is open across probe families (e.g. security has
249
+ * `isolated-protected`, mass-assignment has its own subset); we keep
250
+ * it as a string with documented values rather than a closed enum
251
+ * that needs to be rev'd every time a new class lands. */
252
+ export const ProbeEndpointPlanSchema = z.object({
253
+ path: z.string(),
254
+ method: z.string(),
255
+ planned: z.boolean(),
256
+ classes_planned: z.array(z.string()),
257
+ fields_planned: z.array(z.string()),
258
+ skip_reason: z.string().nullable(),
259
+ });
260
+
261
+ export const ProbeDryRunDataSchema = z.object({
262
+ endpoints: z.array(ProbeEndpointPlanSchema),
263
+ summary: z.object({
264
+ totalEndpoints: z.number().int().nonnegative(),
265
+ planned: z.number().int().nonnegative(),
266
+ skipped: z.number().int().nonnegative(),
267
+ }),
268
+ });
269
+
270
+ /** m-17 / ARV-51: shape of `data` for live probe runs (`zond probe <class>
271
+ * --report json` or the default `--json`). One entry per endpoint with
272
+ * structured findings — no markdown blob. The legacy `data.digest.stdout`
273
+ * field is gone (F3-15 / F4-15). */
274
+ export const ProbeFindingSchema = z.object({
275
+ class: z.string(),
276
+ severity: z.enum(["high", "low", "inconclusive", "ok"]),
277
+ evidence: z.record(z.string(), z.unknown()),
278
+ });
279
+
280
+ export const ProbeEndpointResultSchema = z.object({
281
+ path: z.string(),
282
+ method: z.string(),
283
+ classes_run: z.array(z.string()),
284
+ findings: z.array(ProbeFindingSchema),
285
+ status: z.enum(["ok", "high", "low", "inconclusive", "skipped"]),
286
+ skip_reason: z.string().optional(),
287
+ });
288
+
289
+ export const ProbeRunDataSchema = z.object({
290
+ endpoints: z.array(ProbeEndpointResultSchema),
291
+ summary: z.object({
292
+ totalEndpoints: z.number().int().nonnegative(),
293
+ probed: z.number().int().nonnegative(),
294
+ by_status: z.object({
295
+ ok: z.number().int().nonnegative(),
296
+ high: z.number().int().nonnegative(),
297
+ low: z.number().int().nonnegative(),
298
+ inconclusive: z.number().int().nonnegative(),
299
+ skipped: z.number().int().nonnegative(),
300
+ }),
301
+ }),
302
+ });
303
+
304
+ export const SCHEMAS = {
305
+ envelope: JsonEnvelopeSchema,
306
+ error: ZondErrorSchema,
307
+ errorCode: ZondErrorCodeSchema,
308
+ recommendedAction: RecommendedActionSchema,
309
+ checksRunData: ChecksRunDataSchema,
310
+ checkFinding: CheckFindingSchema,
311
+ "ndjson-events": NdjsonEventSchema,
312
+ probeDryRun: ProbeDryRunDataSchema,
313
+ probeRun: ProbeRunDataSchema,
314
+ } as const;
package/src/cli/output.ts CHANGED
@@ -7,9 +7,25 @@ function useColor(): boolean {
7
7
  return process.stderr.isTTY ?? false;
8
8
  }
9
9
 
10
- export function printError(message: string): void {
10
+ let debugHintShown = false;
11
+
12
+ // ARV-203: when a command catches an unexpected throw and calls
13
+ // `printError(msg, err)`, gate the stack trace behind ZOND_DEBUG=1.
14
+ // Without the env var, append a one-time hint so the user knows the
15
+ // switch exists — the previous behaviour silently dropped TypeError
16
+ // stacks and forced reverse-engineering from the bare message.
17
+ export function printError(message: string, err?: unknown): void {
11
18
  const msg = useColor() ? `${RED}Error: ${message}${RESET}` : `Error: ${message}`;
12
19
  process.stderr.write(msg + "\n");
20
+ if (err === undefined) return;
21
+ if (process.env.ZOND_DEBUG === "1" && err instanceof Error && err.stack) {
22
+ process.stderr.write(err.stack + "\n");
23
+ return;
24
+ }
25
+ if (!debugHintShown) {
26
+ debugHintShown = true;
27
+ process.stderr.write(" hint: set ZOND_DEBUG=1 to print the full stack trace.\n");
28
+ }
13
29
  }
14
30
 
15
31
  export function printSuccess(message: string): void {