11.5.15 The ready set's REPEATABLE `kind` / `priority` are declared as arrays — the document catches up to the route
GET /api/v1/projects/{projectKey}/ready accepts ?kind= and ?priority= repeatedly — parseReadyFilters (lib/api/v1/ready/schema.ts) reads both with params.getAll(…), and both parameter descriptions say "Repeatable" in prose. But lib/api/v1/planning/operations.ts:243–257 declares each one's schema as z.string().min(1) — a SCALAR.
So the published document under-describes the route it documents, and a generated client inherits the error: packages/cli/src/api/schema.d.ts renders kind?: string, which cannot express two kinds. V1Transport.buildUrl encodes one value per key to match (with a comment recording that no operation declares an array — true of the document, not of the server).
Why it must land before 11.5.4
motir ready --kinds epic,story is shipped and reachable: parseKinds (packages/cli/src/commands/read.ts:31) splits the flag on commas and returns an ARRAY, which MotirClient.listReady takes as kinds?: string[]. Porting that method onto v1 against the current declaration means sending one kind and dropping the rest — a filter silently narrowing, which is precisely the class of loss 11.5.4's own acceptance criteria exist to prevent.
The change
lib/api/v1/planning/operations.ts—kindandprioritybecomez.array(z.string().min(1)), emitted as aform/explode: truequery parameter so the wire form stays?kind=a&kind=b(exactly what the route already reads).assigneeIdstays scalar: it is tri-state, not repeatable.lib/api/v1/contractVersion.ts— a PATCH bump, not a minor. The set of requests the server accepts does not change by one byte; the document was wrong and is now right, which is the file's own definition of a patch ("a documentation-only correction"). Add the changelog line.packages/cli/src/api/*— regenerated, sokind?: string[].packages/cli/src/transport.ts—buildUrlappends one entry per element for an ARRAY query value, and the ⚠️ comment is rewritten to say arrays are declared and how they encode. The comment already anticipated this ("If one is ever added, the generated types will say so and this is where it lands").
Scope BOUNDARY
Declaration + encoding only. Does NOT change parseReadyFilters, the route, any response field, or any CLI command — 11.5.4 is what puts the encoder to work.
Acceptance criteria
- The emitted document declares
kindandpriorityas arrays withexplode: true; a test asserts it offemitOpenApiDocument(), not off a fixture. - A REAL request through
V1Transportwith{ kind: ['epic','story'] }puts?kind=epic&kind=storyon the wire, and the route narrows to both kinds — driven against the real handler, not a stub. - A scalar query value still encodes exactly as before (one key, one value), asserted so the array branch cannot regress the common path.
contractVersion.tsis at1.3.1with a changelog line naming this correction.- The generated artifacts are committed and both freshness guards in
tests/cli/generated-api-freshness.test.tspass. - The per-file coverage floor (≥90%) holds on every modified file.
Context refs
lib/api/v1/planning/operations.ts— the two declarations to widen.lib/api/v1/ready/schema.ts—parseReadyFilters, thegetAllthe document must match.packages/cli/src/transport.ts—buildUrl's query encoder and its ⚠️ note.packages/cli/src/commands/read.ts—parseKinds, the shipped multi-kind flag.docs/decisions/cli-v1-client.md— the ADR this keeps true.- Story: 11.5.