@kirrosh/zond 0.22.0 → 0.23.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.
- package/CHANGELOG.md +648 -0
- package/README.md +58 -6
- package/package.json +9 -6
- package/src/cli/argv.ts +122 -0
- package/src/cli/commands/add-api.ts +134 -0
- package/src/cli/commands/api/annotate/idempotency.ts +59 -0
- package/src/cli/commands/api/annotate/index.ts +525 -0
- package/src/cli/commands/api/annotate/lifecycle.ts +74 -0
- package/src/cli/commands/api/annotate/overlay.ts +206 -0
- package/src/cli/commands/api/annotate/pagination.ts +60 -0
- package/src/cli/commands/api/annotate/prompts.ts +183 -0
- package/src/cli/commands/api/annotate/readback.ts +58 -0
- package/src/cli/commands/api/annotate/resources.ts +91 -0
- package/src/cli/commands/api/annotate/seed-bodies.ts +61 -0
- package/src/cli/commands/audit.ts +480 -0
- package/src/cli/commands/bootstrap.ts +710 -0
- package/src/cli/commands/catalog.ts +35 -0
- package/src/cli/commands/check.ts +348 -0
- package/src/cli/commands/checks.ts +756 -0
- package/src/cli/commands/ci-init.ts +43 -0
- package/src/cli/commands/clean.ts +212 -0
- package/src/cli/commands/cleanup.ts +262 -0
- package/src/cli/commands/completions.ts +16 -0
- package/src/cli/commands/coverage.ts +605 -132
- package/src/cli/commands/db.ts +178 -7
- package/src/cli/commands/describe.ts +37 -2
- package/src/cli/commands/discover.ts +1236 -0
- package/src/cli/commands/doctor.ts +607 -0
- package/src/cli/commands/fixtures.ts +402 -0
- package/src/cli/commands/generate.ts +420 -46
- package/src/cli/commands/init/bootstrap.ts +30 -1
- package/src/cli/commands/{init.ts → init/index.ts} +99 -5
- package/src/cli/commands/init/skills.ts +56 -3
- package/src/cli/commands/init/templates/agents.md +65 -61
- package/src/cli/commands/init/templates/skills/zond-checks.md +397 -0
- package/src/cli/commands/init/templates/skills/zond-triage.md +210 -0
- package/src/cli/commands/init/templates/skills/zond.md +592 -125
- package/src/cli/commands/init/templates/zond-config.yml +8 -9
- package/src/cli/commands/prepare-fixtures.ts +135 -0
- package/src/cli/commands/probe/mass-assignment.ts +503 -0
- package/src/cli/commands/probe/security.ts +454 -0
- package/src/cli/commands/probe/static.ts +255 -0
- package/src/cli/commands/probe/webhooks.ts +161 -0
- package/src/cli/commands/probe.ts +459 -0
- package/src/cli/commands/reference.ts +87 -0
- package/src/cli/commands/refresh-api.ts +169 -0
- package/src/cli/commands/remove-api.ts +150 -0
- package/src/cli/commands/report-bundle.ts +318 -0
- package/src/cli/commands/report.ts +241 -0
- package/src/cli/commands/request.ts +379 -4
- package/src/cli/commands/run.ts +842 -53
- package/src/cli/commands/session.ts +244 -0
- package/src/cli/commands/use.ts +18 -1
- package/src/cli/index.ts +20 -3
- package/src/cli/json-envelope.ts +112 -3
- package/src/cli/json-schemas.ts +263 -0
- package/src/cli/program.ts +198 -635
- package/src/cli/resolve.ts +105 -0
- package/src/cli/status-filter.ts +124 -0
- package/src/cli/util/api-context.ts +85 -0
- package/src/cli/version.ts +5 -0
- package/src/core/anti-fp/bootstrap.ts +34 -0
- package/src/core/anti-fp/index.ts +33 -0
- package/src/core/anti-fp/registry.ts +44 -0
- package/src/core/anti-fp/rules/baseline-echo.ts +74 -0
- package/src/core/anti-fp/rules/schemathesis/body_negation_becomes_valid.ts +52 -0
- package/src/core/anti-fp/rules/schemathesis/coverage_phase_boundary_positive.ts +38 -0
- package/src/core/anti-fp/rules/schemathesis/has_unverifiable_mutations.ts +35 -0
- package/src/core/anti-fp/rules/schemathesis/index.ts +24 -0
- package/src/core/anti-fp/rules/schemathesis/string_type_mutation_becomes_valid.ts +53 -0
- package/src/core/anti-fp/rules/subscription-gated/index.ts +11 -0
- package/src/core/anti-fp/rules/subscription-gated/paid-plan-403.ts +75 -0
- package/src/core/anti-fp/types.ts +68 -0
- package/src/core/checks/checks/_crud-helpers.ts +133 -0
- package/src/core/checks/checks/_negative_mutator.ts +133 -0
- package/src/core/checks/checks/_readback-helpers.ts +133 -0
- package/src/core/checks/checks/content_type_conformance.ts +39 -0
- package/src/core/checks/checks/cross_call_references.ts +134 -0
- package/src/core/checks/checks/ensure_resource_availability.ts +62 -0
- package/src/core/checks/checks/idempotency_replay.ts +246 -0
- package/src/core/checks/checks/ignored_auth.ts +211 -0
- package/src/core/checks/checks/index.ts +65 -0
- package/src/core/checks/checks/lifecycle_transitions.ts +273 -0
- package/src/core/checks/checks/missing_required_header.ts +40 -0
- package/src/core/checks/checks/negative_data_rejection.ts +45 -0
- package/src/core/checks/checks/not_a_server_error.ts +27 -0
- package/src/core/checks/checks/open_cors_on_sensitive.ts +131 -0
- package/src/core/checks/checks/pagination_invariants.ts +238 -0
- package/src/core/checks/checks/positive_data_acceptance.ts +36 -0
- package/src/core/checks/checks/rate_limit_headers_absent.ts +77 -0
- package/src/core/checks/checks/response_headers_conformance.ts +74 -0
- package/src/core/checks/checks/response_schema_conformance.ts +30 -0
- package/src/core/checks/checks/status_code_conformance.ts +61 -0
- package/src/core/checks/checks/unsupported_method.ts +63 -0
- package/src/core/checks/checks/use_after_free.ts +78 -0
- package/src/core/checks/index.ts +30 -0
- package/src/core/checks/mode.ts +79 -0
- package/src/core/checks/recommended-action.ts +64 -0
- package/src/core/checks/registry.ts +78 -0
- package/src/core/checks/runner.ts +874 -0
- package/src/core/checks/sarif.ts +230 -0
- package/src/core/checks/stateful.ts +121 -0
- package/src/core/checks/types.ts +189 -0
- package/src/core/classifier/recommended-action.ts +222 -0
- package/src/core/context/current.ts +22 -6
- package/src/core/context/session.ts +78 -0
- package/src/core/coverage/loader.ts +185 -0
- package/src/core/coverage/reasons.ts +300 -0
- package/src/core/diagnostics/db-analysis.ts +151 -11
- package/src/core/diagnostics/failure-class.ts +120 -0
- package/src/core/diagnostics/failure-hints.ts +212 -9
- package/src/core/diagnostics/spec-pointer.ts +99 -0
- package/src/core/diagnostics/suggested-fixes.ts +156 -0
- package/src/core/exporter/case-study/index.ts +270 -0
- package/src/core/exporter/curl.ts +40 -0
- package/src/core/exporter/exporter.ts +48 -0
- package/src/core/exporter/html-report/escape.ts +24 -0
- package/src/core/exporter/html-report/index.ts +479 -0
- package/src/core/exporter/html-report/script.ts +100 -0
- package/src/core/exporter/html-report/styles.ts +408 -0
- package/src/core/generator/chunker.ts +42 -16
- package/src/core/generator/coverage-phase.ts +0 -0
- package/src/core/generator/create-body.ts +89 -0
- package/src/core/generator/data-factory.ts +445 -19
- package/src/core/generator/describe.ts +1 -1
- package/src/core/generator/fixtures-builder.ts +325 -0
- package/src/core/generator/index.ts +7 -5
- package/src/core/generator/openapi-reader.ts +37 -3
- package/src/core/generator/path-param-disambig.ts +114 -0
- package/src/core/generator/resources-builder.ts +648 -0
- package/src/core/generator/schema-utils.ts +11 -3
- package/src/core/generator/serializer.ts +103 -13
- package/src/core/generator/suite-generator.ts +419 -111
- package/src/core/generator/types.ts +8 -0
- package/src/core/identity/identity-file.ts +129 -0
- package/src/core/lint/affects.ts +28 -0
- package/src/core/lint/config.ts +96 -0
- package/src/core/lint/format.ts +42 -0
- package/src/core/lint/index.ts +94 -0
- package/src/core/lint/reporter.ts +128 -0
- package/src/core/lint/rules/consistency.ts +158 -0
- package/src/core/lint/rules/heuristics.ts +97 -0
- package/src/core/lint/rules/strictness.ts +109 -0
- package/src/core/lint/types.ts +96 -0
- package/src/core/lint/walker.ts +248 -0
- package/src/core/meta/meta-store.ts +6 -73
- package/src/core/output/README.md +91 -0
- package/src/core/output/index.ts +13 -0
- package/src/core/output/run.ts +126 -0
- package/src/core/output/types.ts +129 -0
- package/src/core/parser/env-interpolation.ts +104 -0
- package/src/core/parser/filter.ts +57 -0
- package/src/core/parser/schema.ts +129 -4
- package/src/core/parser/types.ts +19 -1
- package/src/core/parser/variables.ts +0 -0
- package/src/core/parser/yaml-parser.ts +58 -12
- package/src/core/probe/bootstrap.ts +34 -0
- package/src/core/probe/dry-run-envelope.ts +57 -0
- package/src/core/probe/mass-assignment-probe-class.ts +198 -0
- package/src/core/probe/mass-assignment-probe.ts +1122 -0
- package/src/core/probe/mass-assignment-template.ts +212 -0
- package/src/core/probe/method-probe.ts +43 -76
- package/src/core/probe/method-shared.ts +69 -0
- package/src/core/probe/negative-probe.ts +183 -149
- package/src/core/probe/orphan-tracker.ts +188 -0
- package/src/core/probe/path-discovery.ts +440 -0
- package/src/core/probe/probe-harness.ts +120 -0
- package/src/core/probe/registry.ts +89 -0
- package/src/core/probe/runner.ts +136 -0
- package/src/core/probe/security-probe-class.ts +201 -0
- package/src/core/probe/security-probe.ts +1453 -0
- package/src/core/probe/shared.ts +505 -0
- package/src/core/probe/static-probe-class.ts +125 -0
- package/src/core/probe/types.ts +165 -0
- package/src/core/probe/verdict-aggregator.ts +33 -0
- package/src/core/probe/webhooks-probe.ts +284 -0
- package/src/core/reporter/console.ts +41 -2
- package/src/core/reporter/index.ts +2 -3
- package/src/core/reporter/json.ts +11 -1
- package/src/core/reporter/junit.ts +27 -12
- package/src/core/reporter/ndjson.ts +37 -0
- package/src/core/reporter/types.ts +3 -0
- package/src/core/runner/assertions.ts +58 -1
- package/src/core/runner/async-pool.ts +108 -0
- package/src/core/runner/auth-path.ts +8 -0
- package/src/core/runner/ci-context.ts +72 -0
- package/src/core/runner/executor.ts +264 -20
- package/src/core/runner/form-encode.ts +51 -0
- package/src/core/runner/http-client.ts +75 -2
- package/src/core/runner/learn-drift.ts +293 -0
- package/src/core/runner/preflight-vars.ts +149 -0
- package/src/core/runner/progress-tracker.ts +73 -0
- package/src/core/runner/rate-limiter.ts +89 -17
- package/src/core/runner/run-kind.ts +39 -0
- package/src/core/runner/schema-validator.ts +312 -0
- package/src/core/runner/send-request.ts +153 -20
- package/src/core/runner/types.ts +38 -0
- package/src/core/secrets/registry.ts +164 -0
- package/src/core/secrets/secrets-file.ts +115 -0
- package/src/core/selectors/operation-filter.ts +144 -0
- package/src/core/setup-api.ts +415 -16
- package/src/core/severity/category.ts +94 -0
- package/src/core/severity/index.ts +121 -0
- package/src/core/spec/layers.ts +154 -0
- package/src/core/util/format-eta.ts +21 -0
- package/src/core/utils.ts +5 -1
- package/src/core/workspace/config.ts +129 -0
- package/src/core/workspace/manifest.ts +283 -0
- package/src/core/workspace/output-rotation.ts +62 -0
- package/src/core/workspace/triage-path.ts +87 -0
- package/src/db/lint-runs.ts +47 -0
- package/src/db/migrate.ts +126 -0
- package/src/db/migrations/0001_run_kind.sql +25 -0
- package/src/db/migrations/sql.d.ts +4 -0
- package/src/db/queries/collections.ts +133 -0
- package/src/db/queries/coverage.ts +9 -0
- package/src/db/queries/dashboard.ts +59 -0
- package/src/db/queries/results.ts +128 -0
- package/src/db/queries/runs.ts +235 -0
- package/src/db/queries/sessions.ts +42 -0
- package/src/db/queries/settings.ts +28 -0
- package/src/db/queries/types.ts +172 -0
- package/src/db/queries.ts +72 -802
- package/src/db/schema.ts +178 -50
- package/src/cli/commands/export.ts +0 -144
- package/src/cli/commands/guide.ts +0 -127
- package/src/cli/commands/init/templates/skills/scenarios.md +0 -97
- package/src/cli/commands/probe-methods.ts +0 -108
- package/src/cli/commands/probe-validation.ts +0 -124
- package/src/cli/commands/serve.ts +0 -114
- package/src/cli/commands/sync.ts +0 -268
- package/src/cli/commands/update.ts +0 -189
- package/src/cli/commands/validate.ts +0 -34
- package/src/core/diagnostics/render-md.ts +0 -112
- package/src/core/exporter/postman.ts +0 -963
- package/src/core/generator/guide-builder.ts +0 -253
- package/src/core/meta/types.ts +0 -19
- package/src/core/parser/index.ts +0 -21
- package/src/core/runner/execute-run.ts +0 -132
- package/src/core/runner/index.ts +0 -12
- package/src/core/sync/spec-differ.ts +0 -38
- package/src/web/data/collection-state.ts +0 -362
- package/src/web/routes/api.ts +0 -314
- package/src/web/routes/dashboard.ts +0 -350
- package/src/web/routes/runs.ts +0 -64
- package/src/web/schemas.ts +0 -121
- package/src/web/server.ts +0 -134
- package/src/web/static/htmx.min.cjs +0 -1
- package/src/web/static/style.css +0 -1148
- package/src/web/views/endpoints-tab.ts +0 -174
- package/src/web/views/explorer-tab.ts +0 -402
- package/src/web/views/health-strip.ts +0 -92
- package/src/web/views/layout.ts +0 -48
- package/src/web/views/results.ts +0 -210
- package/src/web/views/runs-tab.ts +0 -126
- package/src/web/views/suites-tab.ts +0 -181
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: zond-checks
|
|
3
|
+
description: |
|
|
4
|
+
Schemathesis-style depth checks for an API — conformance + security
|
|
5
|
+
probes that go beyond YAML smoke tests. Use when the user asks for:
|
|
6
|
+
"deep audit", "find spec drift", "test edge cases", "boundary value
|
|
7
|
+
coverage", "find security bugs", "broken auth check", "use-after-free",
|
|
8
|
+
"SARIF for code scanning", "GitHub Code Scanning report", "stateful
|
|
9
|
+
invariants", "cross-call drift", "idempotency replay", "pagination
|
|
10
|
+
consistency", "lifecycle state machine". For a full generated test
|
|
11
|
+
pipeline + scenarios + audit chain, hand off to `zond`. For triage
|
|
12
|
+
of a failing run, use `zond-triage`.
|
|
13
|
+
allowed-tools: [Read, Bash(zond *), Bash(bunx zond *), Bash(jq *), Bash(sqlite3 *)]
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
# zond-checks — Depth checks (conformance + security)
|
|
17
|
+
|
|
18
|
+
CLI-only skill. Use *after* a YAML smoke run passes — depth checks
|
|
19
|
+
exercise contract drift, malicious input rejection, broken auth, and
|
|
20
|
+
soft-deleted resource leaks against a live API.
|
|
21
|
+
|
|
22
|
+
The catalog is fixed and self-describing — list it before running so
|
|
23
|
+
the user sees what they'll get:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
zond checks list # registered checks (id, severity, expected)
|
|
27
|
+
zond checks list --json # same, machine-readable
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## When to use
|
|
31
|
+
|
|
32
|
+
| User asks | Run |
|
|
33
|
+
|---|---|
|
|
34
|
+
| "deep audit", "find edge cases" | `zond checks run --api <name>` |
|
|
35
|
+
| "boundary value coverage" | `... --phase coverage` |
|
|
36
|
+
| "find security bugs", "broken auth" | `... --check ignored_auth,use_after_free,ensure_resource_availability` |
|
|
37
|
+
| "is GET returning what POST accepted?", "cross-call drift" | `... --check cross_call_references` (m-20) |
|
|
38
|
+
| "does the API honor Idempotency-Key?", "two-POST replay" | `... --check idempotency_replay` (m-20) |
|
|
39
|
+
| "are paginated lists consistent?", "duplicates across cursor pages" | `... --check pagination_invariants` (m-20) |
|
|
40
|
+
| "does cancel/archive land the resource in the declared state?", "state-machine" | `... --check lifecycle_transitions` (m-20) |
|
|
41
|
+
| "do captured webhook events match spec.webhooks shape?" | `zond probe webhooks --event-log events.jsonl` (m-20) — recipe: docs/recipes/webhook-receiver.md |
|
|
42
|
+
| "schemathesis-style strict mode" | `... --strict-405 --strict-401` (m-18) |
|
|
43
|
+
| "SARIF for GitHub Code Scanning" | `... --report sarif --output zond.sarif` |
|
|
44
|
+
| "stream findings to a pipeline" | `... --report ndjson \| jq -c '.'` |
|
|
45
|
+
| "scan large API faster" | `... --workers auto` (or `--workers 8`) |
|
|
46
|
+
|
|
47
|
+
### Strict-mode флаги (m-18)
|
|
48
|
+
|
|
49
|
+
- **`--strict-405`** — `unsupported_method` принимает только 405 (вместо
|
|
50
|
+
pragmatic 401/403/404/405). Mirror schemathesis V4 default. Включай
|
|
51
|
+
когда target — backend, где политика «undeclared method → 405»
|
|
52
|
+
обязательна (RFC 9110 compliance).
|
|
53
|
+
- **`--strict-401`** — `ignored_auth` no-auth/bogus_auth требует ровно 401
|
|
54
|
+
(вместо любого 4xx). Включай для проверки точности auth-rejection policy.
|
|
55
|
+
|
|
56
|
+
Pragmatic режим (default) — реалистичный для production API'ев где gateway
|
|
57
|
+
часто возвращает 404 на undeclared method или 403 на missing auth.
|
|
58
|
+
|
|
59
|
+
## Iron rules
|
|
60
|
+
|
|
61
|
+
- **NEVER hand-roll these checks in YAML.** The catalog encodes
|
|
62
|
+
schemathesis V4 semantics 1-to-1 — replicating them in YAML drifts
|
|
63
|
+
silently. `zond checks run` is the single source of truth.
|
|
64
|
+
- **NEVER run `--check stateful` without prior `api annotate` review.**
|
|
65
|
+
m-20 stateful checks (cross_call_references, idempotency_replay,
|
|
66
|
+
pagination_invariants, lifecycle_transitions) read `.api-resources.local.yaml`
|
|
67
|
+
for per-API quirks (custom pagination param, non-standard lifecycle
|
|
68
|
+
field, write-only ignore_fields). Defaults catch the obvious; running
|
|
69
|
+
on defaults alone misses API-specific drift. See **Phase pre-0** below.
|
|
70
|
+
- **NEVER ignore `--bootstrap-cleanup-failed`.** Stateful security
|
|
71
|
+
checks (`ignored_auth`, `use_after_free`, `ensure_resource_availability`)
|
|
72
|
+
produce false positives on stale data. If the previous run's
|
|
73
|
+
cleanup failed, pass the flag — they skip with a warning instead.
|
|
74
|
+
- **Auth headers are auto-derived from `--api <name>` `.env.yaml`**
|
|
75
|
+
(`auth_token` → `Authorization: Bearer …`, `api_key` → `X-API-Key`).
|
|
76
|
+
Add explicit ones with `--auth-header 'Name: value'` (repeatable).
|
|
77
|
+
|
|
78
|
+
## Phase pre-0 — Annotation (mandatory for `--check stateful`)
|
|
79
|
+
|
|
80
|
+
> **Heads-up for `pagination_invariants`:** only cursor-style pagination
|
|
81
|
+
> is implemented in this milestone (`cursor`/`next`-token responses).
|
|
82
|
+
> APIs with `type: page` / `type: offset` (GitHub, Linear, Resend, …)
|
|
83
|
+
> are accepted by `annotate apply` but the check short-circuits with
|
|
84
|
+
> "type not implemented" — annotating page-based pagination has **no
|
|
85
|
+
> runtime effect**, skip the dump+apply step for those resources.
|
|
86
|
+
|
|
87
|
+
m-20 stateful checks rely on per-resource config in
|
|
88
|
+
`.api-resources.local.yaml` (overlay that survives `refresh-api`).
|
|
89
|
+
`zond api annotate` is the canonical authoring path: zond emits raw
|
|
90
|
+
spec slices, **agent (you) writes the YAML**, zond validates and
|
|
91
|
+
applies. **zond itself does NOT call any LLM** — agent is the LLM, zond
|
|
92
|
+
is the dumb-tool.
|
|
93
|
+
|
|
94
|
+
Six dump aspects (one per check class):
|
|
95
|
+
|
|
96
|
+
```bash
|
|
97
|
+
zond api annotate dump --api <name> --seed-bodies > /tmp/seed.json
|
|
98
|
+
zond api annotate dump --api <name> --readback > /tmp/readback.json
|
|
99
|
+
zond api annotate dump --api <name> --idempotency > /tmp/idem.json
|
|
100
|
+
zond api annotate dump --api <name> --pagination > /tmp/pag.json
|
|
101
|
+
zond api annotate dump --api <name> --lifecycle > /tmp/life.json
|
|
102
|
+
zond api annotate dump --api <name> --resources > /tmp/orphans.json # optional: new CRUD resources from orphans
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
Restrict scope with `--only r1,r2,r3` on any dump.
|
|
106
|
+
|
|
107
|
+
Agent reads each dump and writes a YAML response file (top-level list
|
|
108
|
+
of entries — see per-check schemas below for the block shape).
|
|
109
|
+
Optional `rationale` and `confidence: high|medium|low` per entry help
|
|
110
|
+
future review.
|
|
111
|
+
|
|
112
|
+
Apply — dry-run first (renders diff + conflicts), then `--yes` to write:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
zond api annotate apply --api <name> --readback --input /tmp/readback.yaml # dry-run
|
|
116
|
+
zond api annotate apply --api <name> --readback --input /tmp/readback.yaml --yes # write
|
|
117
|
+
zond api annotate apply --api <name> --readback --input /tmp/readback.yaml --yes --force # overwrite conflicts
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Conflicts: when an existing field already has a value, apply keeps
|
|
121
|
+
existing by default (renders `! field: (conflict — kept existing; pass
|
|
122
|
+
--yes to overwrite)`). Pass `--force` to overwrite.
|
|
123
|
+
|
|
124
|
+
**Recommended pre-stateful sweep on a new API:**
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
zond api annotate dump --api <name> --seed-bodies > /tmp/seed.json # for prepare-fixtures --seed
|
|
128
|
+
zond api annotate dump --api <name> --readback > /tmp/readback.json # for cross_call_references
|
|
129
|
+
zond api annotate dump --api <name> --pagination > /tmp/pag.json # for pagination_invariants
|
|
130
|
+
zond api annotate dump --api <name> --lifecycle > /tmp/life.json # for lifecycle_transitions
|
|
131
|
+
zond api annotate dump --api <name> --idempotency > /tmp/idem.json # for idempotency_replay
|
|
132
|
+
# … agent generates YAML files for each …
|
|
133
|
+
zond api annotate apply --api <name> --seed-bodies --input /tmp/seed.yaml --yes
|
|
134
|
+
zond api annotate apply --api <name> --readback --input /tmp/readback.yaml --yes
|
|
135
|
+
zond api annotate apply --api <name> --pagination --input /tmp/pag.yaml --yes
|
|
136
|
+
zond api annotate apply --api <name> --lifecycle --input /tmp/life.yaml --yes
|
|
137
|
+
zond api annotate apply --api <name> --idempotency --input /tmp/idem.yaml --yes
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
Each block's YAML format is documented under the per-check section below.
|
|
141
|
+
|
|
142
|
+
## Reading findings
|
|
143
|
+
|
|
144
|
+
Every finding carries a closed-enum `recommended_action` so the agent
|
|
145
|
+
can route without parsing free-form messages:
|
|
146
|
+
|
|
147
|
+
| `recommended_action` | What to do |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `report_backend_bug` | Server returned 5xx / accepted invalid auth / leaked deleted resource. File a backend ticket; do not "fix" the test. |
|
|
150
|
+
| `fix_spec` | Server's behaviour is reasonable but spec doesn't predict it. Update `apis/<name>/spec.json` (or upstream OpenAPI) and `zond refresh-api`. |
|
|
151
|
+
| `tighten_validation` | Server accepted a body that violates the schema. Backend should reject earlier (400/422). |
|
|
152
|
+
| `add_required_header` | Spec marked a header `required: true`; server didn't enforce it. Either enforce it or relax the spec. |
|
|
153
|
+
| `fix_auth_config` | Auth-related failure. Check `apis/<name>/.env.yaml` (`auth_token`, `api_key`) — never log the value. |
|
|
154
|
+
| `fix_network_config` | Transport-level error (timeout / DNS / refused). Verify `base_url` and reachability before re-running. |
|
|
155
|
+
| `wontfix_known_limitation` | Known accepted gap. Don't retry, don't file a bug. |
|
|
156
|
+
|
|
157
|
+
Triage by `recommended_action` first, then by severity. HIGH/CRITICAL
|
|
158
|
+
gates exit-code 1; LOW/MEDIUM is informational.
|
|
159
|
+
|
|
160
|
+
## Output formats
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
zond checks run --api myapi --json # one envelope: findings[] + summary
|
|
164
|
+
zond checks run --api myapi --report sarif --output zond.sarif
|
|
165
|
+
# SARIF v2.1.0 for github/codeql-action/upload-sarif@v3
|
|
166
|
+
zond checks run --api myapi --report ndjson | jq -c '.' # streaming events: check_start, check_result, finding, summary
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
NDJSON event schema is published at `docs/json-schema/ndjson-events.schema.json`
|
|
170
|
+
— pipe through `ajv validate` if you build a downstream consumer.
|
|
171
|
+
|
|
172
|
+
## Scoping a run
|
|
173
|
+
|
|
174
|
+
Long runs feel sluggish on a 200-endpoint spec. Scope down before
|
|
175
|
+
broadening:
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
# Filter operations (regex) — same grammar as `zond generate`
|
|
179
|
+
zond checks run --api myapi --include 'tag:billing,users' --exclude 'method:DELETE'
|
|
180
|
+
|
|
181
|
+
# Pick a vector
|
|
182
|
+
zond checks run --api myapi --mode positive # contract verification only
|
|
183
|
+
zond checks run --api myapi --mode negative # malicious-input probes only
|
|
184
|
+
|
|
185
|
+
# Pick a phase
|
|
186
|
+
zond checks run --api myapi --phase coverage # deterministic boundary values
|
|
187
|
+
zond checks run --api myapi --phase examples # default — one positive + one negative per op
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`--allow-x00` adds the NUL byte (`\x00`) to string boundaries during
|
|
191
|
+
coverage — off by default (some HTTP/JSON stacks panic on it).
|
|
192
|
+
|
|
193
|
+
## Concurrency
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
zond checks run --api myapi --workers auto # min(cpus, 8); usually right
|
|
197
|
+
zond checks run --api myapi --workers 16 # explicit; clamped to 64
|
|
198
|
+
zond checks run --api myapi --workers 8 --rate-limit 50
|
|
199
|
+
# 8 workers, global 50 RPS budget
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
Workers parallelize at the *operation* level — cases inside one
|
|
203
|
+
operation always run sequentially (CRUD chain ordering must be
|
|
204
|
+
preserved). `--rate-limit auto` adapts from `RateLimit-*` response
|
|
205
|
+
headers (RFC 9568); use it on rate-limited APIs to avoid bursting.
|
|
206
|
+
|
|
207
|
+
## "0 findings" doesn't always mean "all green"
|
|
208
|
+
|
|
209
|
+
The summary one-liner now ends with `(N check outcome(s) skipped: …)`
|
|
210
|
+
when probes can't validate (e.g. `response_schema_conformance: no JSON
|
|
211
|
+
Schema on this response branch ×2` when probes ran without auth and
|
|
212
|
+
got a 4xx that the spec only declares for 2xx). Treat skipped probes
|
|
213
|
+
as "not yet exercised", not "passed" — re-run with auth (or via
|
|
214
|
+
`zond run --validate-schema`) to actually cover those branches.
|
|
215
|
+
|
|
216
|
+
## Exit codes
|
|
217
|
+
|
|
218
|
+
| Code | Meaning |
|
|
219
|
+
|---|---|
|
|
220
|
+
| 0 | No HIGH/CRITICAL findings (LOW/MEDIUM may be present). |
|
|
221
|
+
| 1 | At least one HIGH/CRITICAL finding — gate CI on this. |
|
|
222
|
+
| 2 | CLI-input error (bad flag value, unreachable spec, etc.). |
|
|
223
|
+
|
|
224
|
+
## Common combos
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
# Full conformance pass on staging, output SARIF for code scanning
|
|
228
|
+
zond checks run --api staging --report sarif --output zond.sarif --workers auto
|
|
229
|
+
|
|
230
|
+
# Just the security checks (stateful) with explicit auth
|
|
231
|
+
zond checks run --api prod \
|
|
232
|
+
--check ignored_auth,use_after_free,ensure_resource_availability \
|
|
233
|
+
--auth-header 'Authorization: Bearer $TOKEN'
|
|
234
|
+
|
|
235
|
+
# Coverage-phase boundary sweep, NDJSON pipe into a watcher
|
|
236
|
+
zond checks run --api dev --phase coverage --report ndjson | \
|
|
237
|
+
jq -c 'select(.type == "finding") | {check, op: .finding.operation, action: .finding.recommended_action}'
|
|
238
|
+
|
|
239
|
+
# Cross-call POST→GET drift only (m-20, single CRUD-chain check per resource)
|
|
240
|
+
zond checks run --api stripe --check cross_call_references
|
|
241
|
+
```
|
|
242
|
+
|
|
243
|
+
## Cross-call drift (m-20 ARV-169)
|
|
244
|
+
|
|
245
|
+
`cross_call_references` — POST resource → GET resource, diff write-shape
|
|
246
|
+
vs read-shape. Surfaces fields the server silently dropped:
|
|
247
|
+
|
|
248
|
+
- **state_not_persisted** — POST 2xx echoed the field, GET dropped it.
|
|
249
|
+
HIGH-signal: server lied about persisting state.
|
|
250
|
+
- **write_only** — POST accepted, GET dropped. Spec-declared write-only
|
|
251
|
+
fields (passwords, etc.) are auto-filtered.
|
|
252
|
+
|
|
253
|
+
Tunable per-resource in `apis/<name>/.api-resources.yaml` (или
|
|
254
|
+
`.api-resources.local.yaml` overlay):
|
|
255
|
+
|
|
256
|
+
```yaml
|
|
257
|
+
resources:
|
|
258
|
+
- resource: customer
|
|
259
|
+
# … existing fields …
|
|
260
|
+
readback_diff:
|
|
261
|
+
ignore_fields: [metadata, livemode] # API-quirks, suppress
|
|
262
|
+
write_to_read_map:
|
|
263
|
+
tax_id_data: tax_ids # write-shape → read-shape
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
Defaults already filter timestamps (`created_at`, `updated_at`), envelope
|
|
267
|
+
fields (`object`, `_links`), and ETag. Per-API quirks need a yaml line.
|
|
268
|
+
Authored either by hand or via the `zond api annotate dump --readback` →
|
|
269
|
+
agent → `apply` flow (see **Phase pre-0** above). zond emits the
|
|
270
|
+
write+read endpoint slice; agent decides `ignore_fields` /
|
|
271
|
+
`write_to_read_map` and writes the YAML; zond validates + writes to
|
|
272
|
+
`.api-resources.local.yaml`.
|
|
273
|
+
|
|
274
|
+
## Idempotency replay (m-20 ARV-170)
|
|
275
|
+
|
|
276
|
+
`idempotency_replay` — two POSTs with the same `Idempotency-Key` header.
|
|
277
|
+
Server must (a) return the same resource id and (b) bit-identical response
|
|
278
|
+
bodies (modulo timestamps / request-id / etag).
|
|
279
|
+
|
|
280
|
+
- **duplicate_resource** — ids differ → server ignored the key. HIGH.
|
|
281
|
+
- **non_bit_identical** — same id but bodies drift on non-ignored fields
|
|
282
|
+
→ replay isn't truly idempotent. Surfaced in the same HIGH finding via
|
|
283
|
+
`evidence.kind`.
|
|
284
|
+
|
|
285
|
+
Two ways to opt-in per resource:
|
|
286
|
+
|
|
287
|
+
1. Spec declares `Idempotency-Key` as a header parameter on the create
|
|
288
|
+
endpoint → auto-detected, runs with defaults.
|
|
289
|
+
2. `.api-resources.local.yaml` block (preferred — documents intent +
|
|
290
|
+
lets you tune the ignore list). Author via Phase pre-0
|
|
291
|
+
`annotate dump --idempotency` → agent → `apply`:
|
|
292
|
+
|
|
293
|
+
```yaml
|
|
294
|
+
resources:
|
|
295
|
+
- resource: charge
|
|
296
|
+
# … existing fields …
|
|
297
|
+
idempotency:
|
|
298
|
+
header: Idempotency-Key # default; override for non-standard names
|
|
299
|
+
scope: endpoint # informational; `endpoint` | `global`
|
|
300
|
+
ignore_response_fields: # added on top of timestamp/request_id baseline
|
|
301
|
+
- retry_after
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Anti-FP: 429/409 on the 2nd POST → skip with cleanup. No DELETE on the
|
|
305
|
+
group → finding still fires, evidence carries `cleanup_warning`.
|
|
306
|
+
|
|
307
|
+
## Pagination invariants (m-20 ARV-171)
|
|
308
|
+
|
|
309
|
+
`pagination_invariants` — fetch two consecutive cursor pages and assert
|
|
310
|
+
the contract holds:
|
|
311
|
+
|
|
312
|
+
- **duplicate_items** — an item id appears on both page A and page B
|
|
313
|
+
(off-by-one / cursor stops one short). HIGH-signal.
|
|
314
|
+
- **has_more_inconsistent** — page A said `has_more=true`, but page B is
|
|
315
|
+
empty and doesn't flip to `has_more=false`. Surfaces broken end-of-list
|
|
316
|
+
signalling.
|
|
317
|
+
- **partial_page_with_has_more** — page A returns fewer items than the
|
|
318
|
+
requested limit *yet* advertises `has_more=true`. Means the cursor is
|
|
319
|
+
prematurely truncating responses.
|
|
320
|
+
|
|
321
|
+
Cursor-style only in this milestone (Stripe / GitHub / Resend / Linear
|
|
322
|
+
pattern). `page` / `offset` / `token` declarations parse but the check
|
|
323
|
+
short-circuits with a "type not implemented" reason so the yaml block
|
|
324
|
+
stays a stable schema.
|
|
325
|
+
|
|
326
|
+
Auto-detect: if the list endpoint declares `starting_after` / `cursor` /
|
|
327
|
+
`after` / `page_token` as a query parameter, the check runs with
|
|
328
|
+
defaults (`cursor_field=id`, `items_field=data|items|results`,
|
|
329
|
+
`has_more_field=has_more`, `limit=2`).
|
|
330
|
+
|
|
331
|
+
Per-resource yaml override (author via Phase pre-0
|
|
332
|
+
`annotate dump --pagination` → agent → `apply`):
|
|
333
|
+
|
|
334
|
+
```yaml
|
|
335
|
+
resources:
|
|
336
|
+
- resource: customer
|
|
337
|
+
# … existing fields …
|
|
338
|
+
pagination:
|
|
339
|
+
type: cursor # only cursor supported today
|
|
340
|
+
cursor_param: starting_after # Stripe-style; "after" / "cursor" / "page_token" also work
|
|
341
|
+
cursor_field: id # field on each item that feeds the next cursor
|
|
342
|
+
has_more_field: has_more # response field that flips on end-of-list
|
|
343
|
+
limit_param: limit # query param for page size
|
|
344
|
+
default_limit: 2 # probe page size — small on purpose
|
|
345
|
+
items_field: data # array container (falls back to items / results / value)
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
## Lifecycle transitions (m-20 ARV-172)
|
|
349
|
+
|
|
350
|
+
`lifecycle_transitions` — declare a state machine in
|
|
351
|
+
`.api-resources.yaml`, the check creates a resource and walks the
|
|
352
|
+
named actions, asserting:
|
|
353
|
+
|
|
354
|
+
- **undeclared_state** — observed state isn't in declared `states[]`.
|
|
355
|
+
- **wrong_expected_state** — action landed the resource in a state other
|
|
356
|
+
than its declared `expected_state`.
|
|
357
|
+
- **forbidden_transition** — observed (from, to) isn't in declared
|
|
358
|
+
transitions graph.
|
|
359
|
+
- **state_regression_on_replay** — invoking the action a second time
|
|
360
|
+
drifted state instead of staying idempotent.
|
|
361
|
+
- **double_action_5xx** — replay 5xx'd. Idempotent actions should 4xx
|
|
362
|
+
or 2xx, never crash.
|
|
363
|
+
- **action_rejected** — first-call non-2xx (server-side gating). Not a
|
|
364
|
+
contract bug per se, surfaced as INCONCLUSIVE-class info.
|
|
365
|
+
|
|
366
|
+
Manifest validation runs at yaml load (catches cycles, unreachable
|
|
367
|
+
states, missing terminal, actions referencing undeclared states)
|
|
368
|
+
before any HTTP call goes out.
|
|
369
|
+
|
|
370
|
+
Author via Phase pre-0 `annotate dump --lifecycle` → agent → `apply`.
|
|
371
|
+
The dump emits action-endpoint candidates (POST `/{resource}/{id}/cancel`,
|
|
372
|
+
PATCH `/{resource}/{id}/status` etc.); agent decides the state machine
|
|
373
|
+
graph.
|
|
374
|
+
|
|
375
|
+
```yaml
|
|
376
|
+
resources:
|
|
377
|
+
- resource: subscription
|
|
378
|
+
# … existing fields …
|
|
379
|
+
lifecycle:
|
|
380
|
+
field: status
|
|
381
|
+
states: [pending, active, cancelled]
|
|
382
|
+
transitions:
|
|
383
|
+
- from: pending
|
|
384
|
+
to: [active, cancelled]
|
|
385
|
+
- from: active
|
|
386
|
+
to: [cancelled]
|
|
387
|
+
- from: cancelled
|
|
388
|
+
to: [] # terminal
|
|
389
|
+
actions:
|
|
390
|
+
cancel:
|
|
391
|
+
endpoint: POST /v1/subscriptions/{id}/cancel
|
|
392
|
+
expected_state: cancelled
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Action endpoints accept the `{id}` placeholder (replaced with the
|
|
396
|
+
captured create-id) or `{<idParam>}`. Body-less actions are the common
|
|
397
|
+
case; provide `body:` only for actions that demand a request payload.
|
|
@@ -0,0 +1,210 @@
|
|
|
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
|
+
- **`fix_env` overrides `fix_test_logic` at the suite level.** `db
|
|
38
|
+
diagnose` already does this collapse (TASK-70/98) — trust the field
|
|
39
|
+
it returns, don't merge again client-side.
|
|
40
|
+
- **Never read raw response bodies past 8 KB.** The diagnose envelope
|
|
41
|
+
truncates by default; pass `--no-body-cap` only if the user is
|
|
42
|
+
triaging body-shape bugs.
|
|
43
|
+
- **Никогда не выдавать абстрактные «проверьте логи» / «уточните у
|
|
44
|
+
команды».** Если в enum-группе нет конкретного действия — пометить
|
|
45
|
+
`<TODO: clarify>` и выйти, не маскировать пустоту.
|
|
46
|
+
|
|
47
|
+
## Sources & enum routing
|
|
48
|
+
|
|
49
|
+
| Source | How to read | Emits `recommended_action` for |
|
|
50
|
+
|---|---|---|
|
|
51
|
+
| `zond db diagnose <run-id> --json` | per-failure under `data.failures[]` | every fail/error in the run |
|
|
52
|
+
| `zond check spec --api <name> --json` | `data.issues[]` | every lint Issue (always `fix_spec`) |
|
|
53
|
+
| `zond probe mass-assignment --json` | `data.verdicts[]` | per-endpoint verdicts (high/medium/inconclusive-5xx/inconclusive-baseline) |
|
|
54
|
+
| `zond probe security --json` | counts only — read the markdown digest | high / low findings (markdown table) |
|
|
55
|
+
| `zond probe static --json` | `data.files[]` (suite YAMLs to run) | findings surface only after `zond run` → routed via diagnose |
|
|
56
|
+
|
|
57
|
+
`probe security` does not expose findings in `--json`; treat its
|
|
58
|
+
markdown digest as the canonical source for that class and parse
|
|
59
|
+
HIGH/LOW rows by hand.
|
|
60
|
+
|
|
61
|
+
## Phase 1 — locate the run
|
|
62
|
+
|
|
63
|
+
If the user did not name a run id, the default of `zond db diagnose`
|
|
64
|
+
already targets the most recent failing run (TASK-266). Skip straight to
|
|
65
|
+
Phase 2 unless you specifically need an older run:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
zond db runs --limit 5 --json # pick a non-default run id
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
If `trigger=ci`, mention the CI build in the summary. If the user said
|
|
72
|
+
"после моего фикса", take the second-most-recent and pair with
|
|
73
|
+
`zond db compare <prev> <curr> --json` for a regression diff.
|
|
74
|
+
|
|
75
|
+
## Phase 2 — pull the diagnose envelope
|
|
76
|
+
|
|
77
|
+
```bash
|
|
78
|
+
zond db diagnose --json # last failing run (default — TASK-266)
|
|
79
|
+
zond db diagnose <run-id> --json # explicit run
|
|
80
|
+
zond db diagnose --latest --json # last run, even if it passed
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The shape (relevant fields only):
|
|
84
|
+
|
|
85
|
+
```jsonc
|
|
86
|
+
{
|
|
87
|
+
"ok": true,
|
|
88
|
+
"data": {
|
|
89
|
+
"run_id": 42,
|
|
90
|
+
"summary": { "passed": 18, "failed": 7, "errored": 1 },
|
|
91
|
+
"env_issue": { "scope": "suite", "affected_suites": [...], "message": "..." },
|
|
92
|
+
"failures": [
|
|
93
|
+
{
|
|
94
|
+
"suite_name": "crud-projects",
|
|
95
|
+
"test_name": "create project",
|
|
96
|
+
"failure_type": "api_error",
|
|
97
|
+
"recommended_action": "report_backend_bug",
|
|
98
|
+
"request_method": "POST",
|
|
99
|
+
"request_url": "...",
|
|
100
|
+
"response_status": 500,
|
|
101
|
+
"hint": "...",
|
|
102
|
+
"schema_hint": "..."
|
|
103
|
+
}
|
|
104
|
+
]
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
Bucket every failure by `recommended_action`. Display order (highest
|
|
110
|
+
priority first):
|
|
111
|
+
|
|
112
|
+
1. `report_backend_bug` — 5xx / schema_violation / mass-assignment HIGH.
|
|
113
|
+
Bug. Surface excerpt; offer `zond report bundle --include case-study`.
|
|
114
|
+
2. `fix_spec` — emitted only by `zond check spec`. Edit OpenAPI source,
|
|
115
|
+
then `zond refresh-api <name>`.
|
|
116
|
+
3. `fix_auth_config` — 401/403 cluster. Check `auth_token` scope (or run
|
|
117
|
+
`zond doctor --api <name> --missing-only`).
|
|
118
|
+
4. `fix_env` — env_issue cluster. Print `env_issue.message` verbatim;
|
|
119
|
+
point at `.env.yaml` (path is in the envelope).
|
|
120
|
+
5. `fix_fixture` — `prepare-fixtures` miss-* or inconclusive-baseline
|
|
121
|
+
from mass-assignment. Run
|
|
122
|
+
`zond prepare-fixtures --api <name> --apply [--cascade [--seed]]`. If
|
|
123
|
+
the run was post-probe and IDs may be stale, prefer
|
|
124
|
+
`prepare-fixtures --refresh` (TASK-281) and follow with `zond cleanup
|
|
125
|
+
--orphans` (TASK-278) before retrying.
|
|
126
|
+
6. `fix_network_config` — connect-refused / DNS / TLS. Check `base_url`
|
|
127
|
+
reachability; `--proxy` may be needed.
|
|
128
|
+
7. `regenerate_suite` (ARV-42) — 4xx (400/422) on a generator-emitted
|
|
129
|
+
suite under `apis/<name>/tests/`. Editing the YAML is wrong: the
|
|
130
|
+
next `zond audit` overwrites it. Re-run `zond generate --api <name>`
|
|
131
|
+
so newer heuristics apply (e.g. ARV-38 default-string), or refine
|
|
132
|
+
`.api-resources.yaml` hints when the body shape can't be inferred.
|
|
133
|
+
8. `fix_test_logic` — 4xx (400/422) on a manually-authored suite, or any
|
|
134
|
+
leftover assertion failure not absorbed by the buckets above. Phase 4a
|
|
135
|
+
of the `zond` skill: fixture pack first, typed generator second,
|
|
136
|
+
literal third.
|
|
137
|
+
|
|
138
|
+
Within each bucket, collapse by `(suite_name, response_status,
|
|
139
|
+
request_method, root_cause)` and report a count + 1-2 examples. Do
|
|
140
|
+
**not** dump every failure.
|
|
141
|
+
|
|
142
|
+
## Phase 3 — reconcile spec / probe sources
|
|
143
|
+
|
|
144
|
+
Run only what the user's question implies — don't fan out blindly.
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
# spec-level lint (only if user asked about spec drift / contract)
|
|
148
|
+
zond check spec --api <name> --json | jq '.data.issues | group_by(.rule)'
|
|
149
|
+
|
|
150
|
+
# mass-assignment digest (only if user mentioned mass-assign / privilege)
|
|
151
|
+
zond probe mass-assignment --api <name> --json
|
|
152
|
+
# verdicts with recommended_action != null are the actionable subset
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
For `probe security`, the digest is the source. Read the file the user
|
|
156
|
+
named (or `apis/<name>/probes/security-digest.md`) and pull HIGH rows
|
|
157
|
+
plus the `## ⚠️ Cleanup failures` section if present.
|
|
158
|
+
|
|
159
|
+
## Output template
|
|
160
|
+
|
|
161
|
+
Stay terse. Russian by default, mirror the user's language.
|
|
162
|
+
|
|
163
|
+
```
|
|
164
|
+
Run #<id> · <ts> · session=<id?> · trigger=<ci|manual>
|
|
165
|
+
Pass <N> Fail <M> Error <K> Coverage <pct>%
|
|
166
|
+
|
|
167
|
+
⛔ report_backend_bug ×<n>
|
|
168
|
+
· POST /v1/projects → 500 (×3) — TypeError: cannot read 'slug'
|
|
169
|
+
next: zond report bundle <id> --include case-study
|
|
170
|
+
🛠 fix_test_logic ×<n>
|
|
171
|
+
· POST /v1/audiences → 422 expected uuid (×2)
|
|
172
|
+
next: replace {{$randomString}} with {{$uuid}} in audiences.yaml
|
|
173
|
+
🔑 fix_auth_config ×<n>
|
|
174
|
+
· 4 suites all 401 — check auth_token scope
|
|
175
|
+
next: zond doctor --api <name> --missing-only
|
|
176
|
+
🌐 fix_env ×<n>
|
|
177
|
+
· base_url unset (env_issue.scope=run)
|
|
178
|
+
next: edit apis/<name>/.env.yaml → base_url
|
|
179
|
+
📥 fix_fixture ×<n>
|
|
180
|
+
· {{audience_id}} unresolved
|
|
181
|
+
next: zond prepare-fixtures --api <name> --apply --cascade
|
|
182
|
+
📜 fix_spec ×<n> (from check spec)
|
|
183
|
+
· A2 missing operationId on POST /webhooks
|
|
184
|
+
next: edit spec.json → operationId, then zond refresh-api <name>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Skip empty buckets. If `summary.failed + summary.errored == 0`, just
|
|
188
|
+
say "all green" and exit — don't invent work.
|
|
189
|
+
|
|
190
|
+
## When to escalate
|
|
191
|
+
|
|
192
|
+
- **Mixed recommended_action inside one suite (>3 distinct enums):**
|
|
193
|
+
the run was probably aborted mid-setup. Check `env_issue` first; if
|
|
194
|
+
not set, the run hit a fatal early failure — `zond db run <id>
|
|
195
|
+
--status 500 --first-only --json` to find it.
|
|
196
|
+
- **Cleanup failures from `probe security`:** call out at the **top** —
|
|
197
|
+
this means probe mutated state it could not restore. Treat as
|
|
198
|
+
blocking; do not run more probes against the same env until the
|
|
199
|
+
user confirms manual cleanup.
|
|
200
|
+
- **`recommended_action` missing on a verdict you expected to see:**
|
|
201
|
+
TASK-294 stamps it on every issue/finding emitted post-Done. If a
|
|
202
|
+
field is missing, you're probably reading a pre-TASK-294 artifact —
|
|
203
|
+
re-run the source command, don't infer.
|
|
204
|
+
|
|
205
|
+
## Hand-off back to `zond`
|
|
206
|
+
|
|
207
|
+
When the user wants to *act* on the summary (write a fix, file a
|
|
208
|
+
report, re-run the suite), hand off to the parent `zond` skill — it
|
|
209
|
+
owns the YAML edits, `zond report bundle` flow, and the re-run loop.
|
|
210
|
+
This skill stops at the summary.
|