@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,114 @@
1
+ ---
2
+ name: zond-seed
3
+ description: |
4
+ Agent-orchestrated auto-seed: create the fixtures a deep audit needs from
5
+ what the API itself offers, so CRUD depth stops being gated by hand-seeded
6
+ `{{account}}`/`{{customer}}`/… ids. Use when `prepare-fixtures` reports
7
+ `unseededRoots`, when `db diagnose` shows `cascade_skips`, or the user asks
8
+ to "seed fixtures", "create test data", "un-skip the CRUD chains", "raise
9
+ depth". YOU reason (read the API graph, author create-bodies, order them,
10
+ read the 4xx and fix it); zond only EXECUTES (POST + capture id into
11
+ `.env.yaml`). Sibling `zond` runs the full audit; hand back to it once
12
+ fixtures are seeded.
13
+ allowed-tools: [Read, Write, Edit, Bash(zond *), Bash(bunx zond *)]
14
+ ---
15
+
16
+ # zond-seed — agent-orchestrated fixture creation
17
+
18
+ The m-24 endgame: an autonomous seed loop where the DECISION is yours and the
19
+ EXECUTION is zond's. This is **not** a revert of ARV-336 (the blind recursive
20
+ cascade zond removed — 1% success on Stripe). The difference is the feedback
21
+ loop: you read the spec + resource graph, author a create-body, POST it, and
22
+ when the server says 400 you read *why* and fix the body. That is exactly why
23
+ it works where the heuristic engine failed.
24
+
25
+ ## Iron rules (read once, apply always)
26
+
27
+ - **You reason, zond executes.** You author every create-body and pick the
28
+ order; zond only POSTs and captures the returned id. Never ask zond to
29
+ "figure out" a body — that heuristic engine was deleted (ARV-336, m-24) and
30
+ must not grow back. There is no `zond seed` command by design.
31
+ - **No blind cascade — one create at a time, with a feedback loop.** POST a
32
+ body, read the response. On 4xx, read the error message, revise the *specific*
33
+ field it names, retry. Cap at **~3 attempts per resource**, then mark it
34
+ un-seedable and move on. Never fire a chain of creates without reading each
35
+ reply.
36
+ - **Seed only what the API can self-serve.** Fixtures needing external input —
37
+ KYC-verified accounts, verified bank accounts, webhook signing secrets,
38
+ paid-plan / SCIM / TOS-gated resources, or ids that only exist after a real
39
+ event (`issue_id`, `file_id`, `integration_id`) — are **reported, not
40
+ invented** (pairs with `prepare-fixtures` `unseededRoots` and ARV-349/350).
41
+ Guessing a value here just 422s and lies about coverage. Hand those to the
42
+ **`warm-up-target`** skill, which warms them via the target's own SDK/CLI.
43
+ - **Live + throwaway/sandbox + cleanup only.** Never seed against production or
44
+ shared data. Confirm `base_url` is a sandbox/test account first. Track every
45
+ id you create and DELETE it at the end (or seed inside a disposable account /
46
+ Stripe test-clock). If you cannot guarantee cleanup, ask before creating.
47
+ - **Honor prose exclusion.** Specs document mutual exclusion in `description`,
48
+ not machine-readable `oneOf` (Stripe: "You may only specify one of A, B").
49
+ If a 400 says that, drop one member and retry (folded from ARV-347).
50
+
51
+ ## Inputs — what to seed
52
+
53
+ | Signal | Command | Field |
54
+ |---|---|---|
55
+ | Chain-heads gating suites | `zond prepare-fixtures --api <name> --json` | `summary.fixtureGaps.unseededRoots[]` |
56
+ | Empty captures from last run | `zond db diagnose --json` | `cascade_skips[].capture_var` |
57
+ | Dependency order | `apis/<name>/.api-resources.yaml` | each resource's `fkDependencies` |
58
+ | Body schema + last server reply | `zond api annotate dump --seed-bodies --with-last-attempt --api <name>` | `seed_body`, `last_attempt` |
59
+
60
+ `unseededRoots` is your worklist. `fkDependencies` gives the order: a resource
61
+ whose FK points at another must be created *after* its parent (parent id is
62
+ captured first, then referenced). Sort parent-before-child yourself; skip
63
+ cycles and resources whose only dep is external input.
64
+
65
+ **miss-no-list `candidates` (ARV-382):** when prepare-fixtures can't confidently
66
+ derive the owner list for a fixture var, the item carries a `candidates[]` of
67
+ plausible GET/list endpoints (ranked by structural proximity; deprecated ones
68
+ marked `(deprecated)`). zond does NOT pick — that's your call: `zond request`
69
+ the top candidate, read a record, `zond fixtures add <var>=<id>`. An empty
70
+ `candidates` (and no owner) is an honest dead-end: no listable source exists —
71
+ create the resource or obtain the id from a parent flow.
72
+
73
+ ## The loop
74
+
75
+ For each root, parent-first:
76
+
77
+ 1. **Author the body.** `zond api annotate dump --seed-bodies --with-last-attempt`
78
+ gives the schema, a rationale, and `last_attempt` (what zond last POSTed and
79
+ how the server replied). Fill required fields with real-looking values;
80
+ reference already-captured parents as `{{parent_var}}`.
81
+
82
+ 2. **Create + capture** — one command, deterministic:
83
+ ```bash
84
+ zond request POST /v1/accounts --api <name> \
85
+ --body '{"type":"custom","country":"US","capabilities":{...}}' \
86
+ --json-path id --capture account
87
+ ```
88
+ On 2xx zond writes `account=<id>` into `apis/<name>/.env.yaml` (with a
89
+ `.bak` backup) and prints `captured account=<id>`. On non-2xx it writes
90
+ nothing and prints `--capture account skipped — … status=400 …`.
91
+
92
+ 3. **Feedback on failure.** Read the response body. Common fixes:
93
+ - "Missing required field X" → add X.
94
+ - "You may only specify one of A, B" → drop one (prose exclusion).
95
+ - "Invalid <field>" / 422 on an id → the value is external-input; stop
96
+ retrying this root and mark it un-seedable.
97
+ Revise the `--body`, retry. Cap ~3 attempts.
98
+
99
+ 4. **Cascade.** Once a parent id is captured, its children unblock — their
100
+ `{{parent_var}}` now resolves. Walk down the dependency chain.
101
+
102
+ 5. **Verify.** Re-run `zond prepare-fixtures --api <name> --json` — the roots
103
+ you seeded should drop out of `unseededRoots`.
104
+
105
+ ## Cleanup & report
106
+
107
+ - DELETE every id you created (reverse order — children first), or confirm the
108
+ seed account is disposable.
109
+ - Report: **seeded** (var → id), **un-seedable** (var → reason: external input
110
+ / gated / no create endpoint). The un-seedable list is the honest ceiling —
111
+ hand it to the user; do not paper over it with invented values.
112
+
113
+ Hand back to `zond` for the full audit once depth is unblocked. Measure the
114
+ lift: test coverage before vs after seeding.
@@ -0,0 +1,272 @@
1
+ ---
2
+ name: zond-triage
3
+ description: |
4
+ Last-run triage. Use when the user asks "что упало в последнем run", "почему
5
+ красное", "что с ralph-loop'ом сделать", "summary последнего прогона",
6
+ "explain failures", "что мне сейчас править". Reads `recommended_action`
7
+ enum from `zond db diagnose`, `zond check spec`, and `zond probe <class>` JSON
8
+ artifacts and emits an actionable summary grouped by next-step. No LLM
9
+ classification — every line is routed by the enum value emitted by zond.
10
+ allowed-tools: [Read, Bash(zond *), Bash(bunx zond *), Bash(jq *)]
11
+ ---
12
+
13
+ # zond-triage — last-run summary
14
+
15
+ Narrow skill: the user already has a finished run (or a recent
16
+ `probe <class>` / `check spec` artifact) and wants to know **what failed and
17
+ what to do next**. Sibling `zond` does the full audit + writes
18
+ scenarios; this one only reads.
19
+
20
+ ## Iron rules
21
+
22
+ - **Route on `recommended_action`, not on the message string.** Every zond
23
+ artifact stamps a closed enum: `report_backend_bug | fix_test_logic |
24
+ fix_auth_config | fix_network_config | fix_env | fix_spec |
25
+ fix_fixture | regenerate_suite | tighten_validation | add_required_header |
26
+ wontfix_known_limitation`. The last three (m-15 ARV-11) carry
27
+ depth-check findings from `zond checks run`; `regenerate_suite`
28
+ (m-16 ARV-42) means the failing YAML was emitted by `zond generate`
29
+ and editing it would be clobbered — re-run `zond generate --api
30
+ <name>` (or refine `.api-resources.yaml`) instead. Same triage rules
31
+ apply across the board: route by enum value. Group by enum, then
32
+ summarise. Never re-classify with prose heuristics.
33
+ - **One actionable line per group.** The agent-directive *is* the next
34
+ command — don't pad with "consider checking...".
35
+ - **`report_backend_bug` / 5xx → STOP, surface, do not edit `expect:`.**
36
+ Same iron rule as the parent `zond` skill.
37
+ - **Never read raw response bodies past 8 KB.** The diagnose envelope
38
+ truncates by default; to see full bodies, bundle the run instead
39
+ (`zond report bundle <id> --no-body-cap`) — only when the user is
40
+ triaging body-shape bugs.
41
+ - **Никогда не выдавать абстрактные «проверьте логи» / «уточните у
42
+ команды».** Если в enum-группе нет конкретного действия — пометить
43
+ `<TODO: clarify>` и выйти, не маскировать пустоту.
44
+
45
+ ## Sources & enum routing
46
+
47
+ | Source | How to read | Emits `recommended_action` for |
48
+ |---|---|---|
49
+ | `zond db diagnose <run-id> --json` | per-failure under `data.failures[]` | every fail/error in the run |
50
+ | `zond check spec --api <name> --json` | `data.issues[]` | every lint Issue (always `fix_spec`) |
51
+ | `zond probe mass-assignment --json` | `data.endpoints[]` (action under `findings[].evidence.recommended_action`) | per-endpoint verdicts (high/medium/inconclusive-5xx/inconclusive-baseline) |
52
+ | `zond probe security --json` | counts only — read the markdown digest | high / low findings (markdown table) |
53
+ | `zond probe static --json` | `data.files[]` (suite YAMLs to run) | findings surface only after `zond run` → routed via diagnose |
54
+
55
+ `probe security` does not expose findings in `--json`; treat its
56
+ markdown digest as the canonical source for that class and parse
57
+ HIGH/LOW rows by hand.
58
+
59
+ ## Phase 1 — locate the run
60
+
61
+ If the user did not name a run id, the default of `zond db diagnose`
62
+ already targets the most recent failing run (TASK-266). Skip straight to
63
+ Phase 2 unless you specifically need an older run:
64
+
65
+ ```bash
66
+ zond db runs --limit 5 --json # pick a non-default run id
67
+ ```
68
+
69
+ If `trigger=ci`, mention the CI build in the summary. If the user said
70
+ "после моего фикса", take the second-most-recent and pair with
71
+ `zond db compare <prev> <curr> --json` for a regression diff. Besides
72
+ status transitions, the payload carries `.data.body_changes[]` (ARV-339) —
73
+ per-test field-level response-shape diff (`added` / `removed` /
74
+ `type_changed`), i.e. how the contract moved even where status stayed green.
75
+ Each change carries `scope` (ARV-352): `container` = response envelope /
76
+ pagination skeleton (real drift), `element` = a field inside a collection
77
+ item (path crosses `[]`). On list/log endpoints two runs return DIFFERENT
78
+ objects, so `element`-scoped changes are schema-of-union variance across the
79
+ re-sampled set — NOT contract drift. `summary.bodyChangesContainer` /
80
+ `bodyChangesElement` split the count so you can tell "12 field diffs, all
81
+ element-scope on /v1/events" (data variance) from real envelope drift.
82
+
83
+ ## Phase 2 — pull the diagnose envelope
84
+
85
+ ```bash
86
+ zond db diagnose --json # last failing run (default — TASK-266)
87
+ zond db diagnose <run-id> --json # explicit run
88
+ zond db diagnose --latest --json # last run, even if it passed
89
+ zond db diagnose --report yaml # same payload as YAML (ARV-338) — for run snapshots you keep/diff as text
90
+ # ARV-380: aggregate by_recommended_action across a run SET (same --union
91
+ # vocabulary as `zond coverage`) instead of looping per run and merging:
92
+ zond db diagnose --union session --json # all runs in the active session
93
+ zond db diagnose --union since:2h --api <name> --json # runs in a time window (scoped to a collection)
94
+ zond db diagnose --union runs:263,266,269 --json # an explicit run-id set
95
+ ```
96
+
97
+ The shape (relevant fields only):
98
+
99
+ ```jsonc
100
+ {
101
+ "ok": true,
102
+ "data": {
103
+ "run_id": 42,
104
+ "summary": { "passed": 18, "failed": 7, "errored": 1 },
105
+ "failures": [
106
+ {
107
+ "suite_name": "crud-projects",
108
+ "test_name": "create project",
109
+ "failure_type": "api_error",
110
+ "recommended_action": "report_backend_bug",
111
+ "request_method": "POST",
112
+ "request_url": "...",
113
+ "response_status": 500
114
+ }
115
+ ]
116
+ }
117
+ }
118
+ ```
119
+
120
+ Bucket every failure by `recommended_action`. Display order (highest
121
+ priority first):
122
+
123
+ 1. `report_backend_bug` — 5xx / schema_violation / mass-assignment HIGH.
124
+ Bug. Surface excerpt; offer `zond report bundle --include case-study`.
125
+ 2. `fix_spec` — emitted only by `zond check spec`. Edit OpenAPI source,
126
+ then `zond refresh-api <name>`.
127
+ 3. `fix_auth_config` — 401/403 cluster. Check `auth_token` scope (or run
128
+ `zond doctor --api <name> --missing-only`).
129
+ 4. `fix_env` — unresolved variables / broken base_url. Point at
130
+ `.env.yaml` and the failing `request_url` values (unresolved
131
+ `{{var}}` placeholders are visible right in them).
132
+ 5. `fix_fixture` — `prepare-fixtures` miss-* or inconclusive-baseline
133
+ from mass-assignment. Run `zond prepare-fixtures --api <name> --apply`
134
+ (single-pass); fill any remaining gaps by hand (`fixtures add` /
135
+ editing `.env.yaml`). If the run was post-probe and IDs may be stale,
136
+ prefer `prepare-fixtures --refresh` (TASK-281) and follow with `zond
137
+ cleanup --orphans` (TASK-278) before retrying.
138
+ 6. `fix_network_config` — connect-refused / DNS / TLS. Check `base_url`
139
+ reachability; `--proxy` may be needed.
140
+ 7. `regenerate_suite` (ARV-42) — 4xx (400/422) on a generator-emitted
141
+ suite under `apis/<name>/tests/`. Prefer re-running `zond generate
142
+ --api <name>` so newer generation applies (e.g. ARV-38 default-string),
143
+ or refine `.api-resources.yaml` hints when the body shape can't be
144
+ inferred. If you DO hand-edit the YAML, delete its `# Auto-generated`
145
+ header so regenerate preserves it (ARV-361) — otherwise a re-run
146
+ regenerates it; `--force` overwrites even header-stripped files.
147
+ 8. `fix_test_logic` — 4xx (400/422) on a manually-authored suite, or any
148
+ leftover assertion failure not absorbed by the buckets above. Phase 4a
149
+ of the `zond` skill: fixture pack first, typed generator second,
150
+ literal third.
151
+
152
+ Within each bucket, collapse by `(suite_name, response_status,
153
+ request_method, root_cause)` and report a count + 1-2 examples. Do
154
+ **not** dump every failure.
155
+
156
+ ### Shortcut: `by_recommended_action` envelope (ARV-101/ARV-228)
157
+
158
+ `zond db diagnose --json` ships a pre-aggregated envelope keyed by the
159
+ `recommended_action` enum so triage agents skip the `jq | group_by`
160
+ step. Each bucket carries up to 5 examples with full request context
161
+ (method, path, status, trimmed reason) — enough to render the output
162
+ template below without re-fetching `failures[]`.
163
+
164
+ Shape (extracted from `.data.by_recommended_action`):
165
+
166
+ ```jsonc
167
+ {
168
+ "fix_auth_config": {
169
+ "count": 4,
170
+ "examples": [
171
+ {
172
+ "suite": "github-smoke",
173
+ "test": "GetNotifications",
174
+ "method": "GET",
175
+ "path": "/notifications",
176
+ "status": 401,
177
+ "reason": "expected 200, got 401"
178
+ }
179
+ // … up to 5 entries
180
+ ]
181
+ },
182
+ "report_backend_bug": { "count": 12, "examples": [ … ] }
183
+ }
184
+ ```
185
+
186
+ Iterate the priority order in the table above (`report_backend_bug` →
187
+ `fix_test_logic`); for each present key, `count + examples` is enough
188
+ to build the per-bucket section. Fall back to `failures[]` only when
189
+ you need details outside the example slice (full response body, the
190
+ 6th example, etc).
191
+
192
+ ## Phase 3 — reconcile spec / probe sources
193
+
194
+ Run only what the user's question implies — don't fan out blindly.
195
+
196
+ ```bash
197
+ # spec-level lint (only if user asked about spec drift / contract)
198
+ zond check spec --api <name> --json | jq '.data.issues | group_by(.rule)'
199
+
200
+ # mass-assignment digest (only if user mentioned mass-assign / privilege)
201
+ zond probe mass-assignment --api <name> --json
202
+ # verdicts with recommended_action != null are the actionable subset
203
+ ```
204
+
205
+ For `probe security`, the digest is the source. Read the file the user
206
+ named (or `apis/<name>/probes/security-digest.md`) and pull HIGH rows
207
+ plus the `## ⚠️ Cleanup failures` section if present.
208
+
209
+ ### Cross-phase double-emit (ARV-358)
210
+
211
+ A single backend defect surfaces in more than one phase stream, so a naive
212
+ HIGH count over-reports. The `checks` phase (`30-checks.ndjson`, e.g.
213
+ `not_a_server_error`) and the `stateful` phase (`40-stateful.ndjson`, e.g.
214
+ `cursor_boundary_fuzzing`) can both flag the *same* endpoint 5xx — that's
215
+ one defect counted 3–4×. zond does NOT dedup this for you: the check_ids
216
+ differ, so collapsing them is a "same root cause" judgment (attribution),
217
+ which is your job, not the tool's. When counting, **group by `(method,
218
+ path, status)` across phase streams**, not by raw finding count — one
219
+ `GET /v1/billing/alerts → 500` is one defect even if it appears 4 times.
220
+
221
+ ## Output template
222
+
223
+ Stay terse. Russian by default, mirror the user's language.
224
+
225
+ ```
226
+ Run #<id> · <ts> · session=<id?> · trigger=<ci|manual>
227
+ Pass <N> Fail <M> Error <K> Coverage <pct>%
228
+
229
+ ⛔ report_backend_bug ×<n>
230
+ · POST /v1/projects → 500 (×3) — TypeError: cannot read 'slug'
231
+ next: zond report bundle <id> --include case-study
232
+ 🛠 fix_test_logic ×<n>
233
+ · POST /v1/audiences → 422 expected uuid (×2)
234
+ next: replace {{$randomString}} with {{$uuid}} in audiences.yaml
235
+ 🔑 fix_auth_config ×<n>
236
+ · 4 suites all 401 — check auth_token scope
237
+ next: zond doctor --api <name> --missing-only
238
+ 🌐 fix_env ×<n>
239
+ · base_url unset — request_url resolved to "/v1/projects"
240
+ next: edit apis/<name>/.env.yaml → base_url
241
+ 📥 fix_fixture ×<n>
242
+ · {{audience_id}} unresolved
243
+ next: zond prepare-fixtures --api <name> (reports the gap; fill it via `fixtures add` / .env.yaml)
244
+ 📜 fix_spec ×<n> (from check spec)
245
+ · A2 missing operationId on POST /webhooks
246
+ next: edit spec.json → operationId, then zond refresh-api <name>
247
+ ```
248
+
249
+ Skip empty buckets. If `summary.failed + summary.errored == 0`, just
250
+ say "all green" and exit — don't invent work.
251
+
252
+ ## When to escalate
253
+
254
+ - **Mixed recommended_action inside one suite (>3 distinct enums):**
255
+ the run was probably aborted mid-setup. Look for unresolved `{{var}}`
256
+ in `request_url` first; if none, the run hit a fatal early failure —
257
+ `zond db run <id> --status 500 --json` to find it.
258
+ - **Cleanup failures from `probe security`:** call out at the **top** —
259
+ this means probe mutated state it could not restore. Treat as
260
+ blocking; do not run more probes against the same env until the
261
+ user confirms manual cleanup.
262
+ - **`recommended_action` missing on a verdict you expected to see:**
263
+ TASK-294 stamps it on every issue/finding emitted post-Done. If a
264
+ field is missing, you're probably reading a pre-TASK-294 artifact —
265
+ re-run the source command, don't infer.
266
+
267
+ ## Hand-off back to `zond`
268
+
269
+ When the user wants to *act* on the summary (write a fix, file a
270
+ report, re-run the suite), hand off to the parent `zond` skill — it
271
+ owns the YAML edits, `zond report bundle` flow, and the re-run loop.
272
+ This skill stops at the summary.