@shipeasy/openapi 3.2.0 → 3.4.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 (40) hide show
  1. package/README.md +1 -1
  2. package/dist/{chunk-RTN572TI.js → chunk-JJA7XEPU.js} +91 -1
  3. package/dist/chunk-JJA7XEPU.js.map +1 -0
  4. package/dist/{chunk-DW33MG4B.js → chunk-Z3CY5Y44.js} +514 -126
  5. package/dist/chunk-Z3CY5Y44.js.map +1 -0
  6. package/dist/{client-BPVn4hMC.d.ts → client-CkRbr8I2.d.ts} +1544 -212
  7. package/dist/client.d.ts +1 -1
  8. package/dist/client.js +23 -1
  9. package/dist/custom.d.ts +5 -5
  10. package/dist/custom.js +128 -84
  11. package/dist/custom.js.map +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +24 -2
  14. package/dist/index.js.map +1 -1
  15. package/dist/schemas.d.ts +1935 -963
  16. package/dist/schemas.js +141 -1
  17. package/openapi-sdk.json +31 -9
  18. package/openapi.json +10449 -8118
  19. package/openapi.yaml +2274 -634
  20. package/package.json +1 -1
  21. package/spec/components/schemas/alert-rules.yaml +434 -10
  22. package/spec/components/schemas/alerts.yaml +9 -7
  23. package/spec/components/schemas/common.yaml +2 -2
  24. package/spec/components/schemas/connectors.yaml +69 -6
  25. package/spec/components/schemas/events.yaml +20 -9
  26. package/spec/components/schemas/keys.yaml +39 -0
  27. package/spec/components/schemas/metrics.yaml +131 -251
  28. package/spec/components/schemas/ops.yaml +471 -29
  29. package/spec/components/schemas/projects.yaml +18 -0
  30. package/spec/components/schemas/search.yaml +1 -0
  31. package/spec/components/schemas/tags.yaml +91 -0
  32. package/spec/openapi.yaml +56 -0
  33. package/spec/paths/alerts.yaml +5 -3
  34. package/spec/paths/i18n.yaml +2 -1
  35. package/spec/paths/keys.yaml +79 -0
  36. package/spec/paths/metrics.yaml +26 -17
  37. package/spec/paths/ops.yaml +514 -11
  38. package/spec/paths/tags.yaml +270 -0
  39. package/dist/chunk-DW33MG4B.js.map +0 -1
  40. package/dist/chunk-RTN572TI.js.map +0 -1
@@ -3,18 +3,31 @@
3
3
  operationId: listOpsItems
4
4
  summary: List the operational queue
5
5
  description: |-
6
- Returns the unified ops queue (bugs, feature requests, errors, alerts) in work order — highest priority first, oldest first within a priority — so consumers work it top-down. Filter by `type` and/or `status`, and cap with `limit`. Human-gated holding states (items awaiting human sign-off in the dashboard) are never returned by `all`/default status.
6
+ Returns the unified ops queue (bugs, feature requests, errors, alerts, measurement plans) in work order — highest priority first, oldest first within a priority — so consumers work it top-down. Every filter is applied in SQL before paging, and filters combine with AND. Human-gated holding states (items awaiting human sign-off in the dashboard) are never returned by `all`/default status.
7
+
8
+ **Filters:** `type` (one item type), `status` (one lifecycle status, or `unresolved` — everything not yet `resolved`/`wont_fix`), `priority` (one triage priority), `owner` (one person or agent), and `scope=ready` — the items ready to be picked up right now: `open`, with nobody working them (no open run), and either unowned or reopened (sent back to `open` after an earlier run finished).
9
+
10
+ **Paging:** `limit` is the page size and `offset` the number of items to skip. The order is stable, so walk the queue with `offset += limit`; a page shorter than `limit` is the last one.
7
11
 
8
12
  **Use case:** Pull the open queue to triage — e.g. every `bug` still `open` — before working items down one by one.
9
13
  tags:
10
14
  - Ops
11
15
  parameters:
12
16
  - $ref: ../components/parameters.yaml#/ProjectId
17
+ # This enum is the third hand-written copy of the item-type list (the two
18
+ # response schemas in components/schemas/ops.yaml hold the others — there is
19
+ # no OpsItemType component to $ref, since extracting one would retype `type`
20
+ # as a TS enum in every generated client). __tests__/spec.test.ts pins the
21
+ # copies together: it drifted once, and `measure_plan` reached both responses
22
+ # while the filter still rejected it.
13
23
  - name: type
14
24
  in: query
15
25
  required: false
16
- description: Filter by item type (`bug`/`feature_request`/`error`/`alert`), or `all`.
26
+ description: >-
27
+ Filter by item type, or `all` (the default). Every type a returned item
28
+ can carry is filterable, including the auto-filed ones.
17
29
  schema:
30
+ default: all
18
31
  anyOf:
19
32
  - type: string
20
33
  enum:
@@ -22,29 +35,92 @@
22
35
  - feature_request
23
36
  - error
24
37
  - alert
25
- description: Queue item type. `bug` and `feature_request` are user-fileable; `error` and `alert` tickets are auto-filed by the platform.
38
+ - measure_plan
39
+ description: Queue item type. `bug` and `feature_request` are user-fileable; `error`, `alert`, and `measure_plan` tickets are auto-filed by the platform.
26
40
  - type: string
27
41
  const: all
28
42
  - name: status
29
43
  in: query
30
44
  required: false
31
45
  description: >-
32
- Filter by lifecycle status, or `all`. The human-gated holding state
33
- (`pending_approval`) is excluded from `all`/default and returned only
34
- when requested as the exact status.
46
+ Filter by one lifecycle status, `unresolved` for every status that
47
+ is not `resolved` or `wont_fix`, or `all` for every status. Defaults
48
+ to `all` over HTTP; the CLI and MCP tool default to `unresolved`, so
49
+ pass `all` there to include resolved and won't-fix items. The
50
+ human-gated holding state (`pending_approval`) is excluded from
51
+ `unresolved` and `all`, and returned only when requested as the exact
52
+ status.
35
53
  schema:
54
+ default: all
36
55
  anyOf:
37
56
  - $ref: ../components/schemas/ops.yaml#/OpsItemStatus
57
+ - type: string
58
+ const: unresolved
59
+ - type: string
60
+ const: all
61
+ # The CLI and MCP send `unresolved` when the caller omits `status`: an
62
+ # agent asking for "the queue" wants the work still to do, not every
63
+ # resolved and won't-fix item ever filed. The HTTP API keeps `all` — the
64
+ # dashboard and the mobile app read the whole queue through it.
65
+ x-cli:
66
+ default: unresolved
67
+ x-mcp:
68
+ default: unresolved
69
+ - name: priority
70
+ in: query
71
+ required: false
72
+ description: >-
73
+ Filter by triage priority, or `all` (the default). Items with no
74
+ priority set are returned only under `all`.
75
+ schema:
76
+ default: all
77
+ anyOf:
78
+ - $ref: ../components/schemas/ops.yaml#/OpsItemPriority
38
79
  - type: string
39
80
  const: all
81
+ - name: scope
82
+ in: query
83
+ required: false
84
+ description: >-
85
+ `ready` narrows to the items ready to be picked up right now: status
86
+ `open`, no open run (nobody has acked it and is still working), and
87
+ either unowned (no person and no agent) or reopened (sent back to
88
+ `open` after an earlier run finished). Leave `status` unset with it.
89
+ `all` (the default) applies no such narrowing.
90
+ schema:
91
+ type: string
92
+ enum:
93
+ - all
94
+ - ready
95
+ default: all
40
96
  - name: limit
41
97
  in: query
42
98
  required: false
43
- description: Max items to return (1–500).
99
+ description: >-
100
+ Page size — max items to return (1–500). A page shorter than `limit`
101
+ is the last one.
44
102
  schema:
45
103
  type: integer
46
104
  minimum: 1
47
105
  maximum: 500
106
+ default: 200
107
+ # The MCP tool makes the page size a required input (and refuses the call
108
+ # without it) so an agent sizes its own page instead of silently pulling
109
+ # 200 hydrated rows into its context. The HTTP API and the CLI keep the
110
+ # default.
111
+ x-mcp:
112
+ required: true
113
+ - name: offset
114
+ in: query
115
+ required: false
116
+ description: >-
117
+ Number of items to skip before the page starts. Defaults to 0. The
118
+ order is stable, so `offset += limit` walks the queue page by page.
119
+ schema:
120
+ type: integer
121
+ minimum: 0
122
+ maximum: 100000
123
+ default: 0
48
124
  - name: owner
49
125
  in: query
50
126
  required: false
@@ -52,8 +128,7 @@
52
128
  Narrow to items owned by one person OR one agent. Matches a person by
53
129
  `users.id`, email, or display name, and an agent by connector id,
54
130
  display name, or kebab-case handle — e.g. `owner=Claude` or
55
- `owner=alice@acme.dev`. Case-insensitive exact match, applied over the
56
- returned page.
131
+ `owner=alice@acme.dev`. Case-insensitive exact match.
57
132
  schema:
58
133
  type: string
59
134
  responses:
@@ -99,6 +174,30 @@
99
174
  - FORBIDDEN
100
175
  x-cli:
101
176
  name: list
177
+ # The MCP tool description, verbatim — the generator otherwise keeps only the
178
+ # first paragraph (capped), which is too short to say how to filter and page.
179
+ x-mcp:
180
+ description: >-
181
+ List the operational queue (bugs, feature requests, errors, alerts,
182
+ measurement plans) in work order — highest priority first, oldest first
183
+ within a priority.
184
+ PAGING: `limit` (page size, 1–500) is REQUIRED — the call fails without
185
+ it. Start at `offset: 0` and add `limit` to `offset` for the next page;
186
+ a page shorter than `limit` is the last one.
187
+ FILTERS (all optional, combined with AND, applied before paging):
188
+ `type` = bug | feature_request | error | alert | measure_plan;
189
+ `status` = open | in_progress | investigating_by_ai | blocked |
190
+ ready_for_qa | resolved | wont_fix | pending_approval | unresolved |
191
+ all — DEFAULTS TO `unresolved` (omitted = items still being worked:
192
+ open, in_progress, blocked, ready_for_qa…; no resolved or wont_fix
193
+ ones). Pass `status: "all"` to include resolved and wont_fix too
194
+ (pending_approval is only returned when asked for exactly);
195
+ `priority` = critical | high | medium | nice_to_have;
196
+ `owner` = a person (id, email or name) or an agent (connector id, name
197
+ or handle, e.g. "Claude");
198
+ `scope: "ready"` = what to work on now — open items nobody is working
199
+ (no open run) that are unowned or were reopened after an earlier run.
200
+ Use `scope: "ready"` to pick the next item, then `ops_ack` it.
102
201
  post:
103
202
  operationId: createOpsItem
104
203
  summary: File a queue item
@@ -195,6 +294,8 @@
195
294
 
196
295
  The project is the key's own project; there is no `X-Project-Id` to pass and no way to file into someone else's queue. Repeat submissions of the same title dedupe against the open ticket already tracking it, which returns `200` with `deduped: true` instead of filing again.
197
296
 
297
+ Send a `dedupKey` to own that grain yourself — the same key from a monitor, a job, or a retried install re-triggers its open ticket: the ticket's fields are refreshed from the new payload and a "re-triggered" comment is appended (`200` with `deduped: true, updated: true`), so one recurring failure stays one ticket with its history intact.
298
+
198
299
  This endpoint is served by the Shipeasy **edge worker** (`api.shipeasy.ai`), not the admin API — see `servers` below.
199
300
 
200
301
  **Use case:** `shipeasy setup` fails on a customer's machine and self-reports the failure with the user's consent — `{ "title": "Setup failed at Feature installs", "stepsToReproduce": "…", "actualResult": "…" }`.
@@ -281,7 +382,7 @@
281
382
  description: |-
282
383
  Files one feature request onto a project's queue, awaiting human approval. The feature-request counterpart to `POST /ops/bug`, with the same three gates: a `client` key carrying `tickets:public_create`, a project that has opted in, and a `pending_approval` state forced server-side.
283
384
 
284
- The project is the key's own project; there is no `X-Project-Id` to pass. Repeat submissions of the same title dedupe against the open ticket already tracking it, which returns `200` with `deduped: true` instead of filing again.
385
+ The project is the key's own project; there is no `X-Project-Id` to pass. Repeat submissions of the same title dedupe against the open ticket already tracking it, which returns `200` with `deduped: true` instead of filing again. A `dedupKey` works exactly as on `POST /ops/bug`: a repeat carrying the same key refreshes the open ticket and comments that it was re-triggered.
285
386
 
286
387
  This endpoint is served by the Shipeasy **edge worker** (`api.shipeasy.ai`), not the admin API — see `servers` below.
287
388
 
@@ -607,6 +708,11 @@
607
708
  list` and use one of those (or connect the agent under Settings →
608
709
  Triggers).
609
710
 
711
+ **Launching.** When the named agent has a connected trigger and you pass
712
+ no `sessionId`, the ack also fires that trigger — a new provider run
713
+ starts working the item. Pass `launch: false` to only claim the item and
714
+ record the run (you are doing the work yourself), without starting one.
715
+
610
716
  **Completion.** The run closes automatically on the loop's final actions —
611
717
  linking the fixing PR (`link-pr`), an ops-notify escalation, or a
612
718
  completion status change (`ready_for_qa`/`resolved`) — and the dashboard
@@ -728,7 +834,9 @@
728
834
  (`kind: investigated`), a blocking question for the team (`kind:
729
835
  question`), or how to verify the fix (`kind: ready_for_qa` with
730
836
  `qaNotes`). Append-only and create-only, so it is safe for restricted ops
731
- keys.
837
+ keys. For a decision between options you can name, ask a structured
838
+ question instead (`ops questions ask`) — it is answerable in one tap and
839
+ the answer comes back to your run.
732
840
 
733
841
  **Use case:** After working an item, leave a findings write-up (summary,
734
842
  markdown findings, sources inspected, confidence) so the team — and the
@@ -871,6 +979,401 @@
871
979
  positional:
872
980
  - handle
873
981
  - investigationId
982
+ /api/admin/ops/{handle}/questions:
983
+ get:
984
+ operationId: listOpsQuestions
985
+ summary: List an item's questions
986
+ description: |-
987
+ The structured questions asked on a queue item, with their answers —
988
+ newest first (max 100). Pull this to read the answers to questions you
989
+ asked: an answered question reads `status: completed` and carries
990
+ `answer.selected` (the option labels picked) and `answer.other` (the
991
+ free-text "Other" reply, or `null`).
992
+
993
+ **Use case:** You asked with `delivery: poll` from a live session — poll
994
+ this until your questions read `completed`, then continue with the answers.
995
+ tags:
996
+ - Questions
997
+ parameters:
998
+ - $ref: ../components/parameters.yaml#/ProjectId
999
+ - name: handle
1000
+ in: path
1001
+ required: true
1002
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1003
+ schema:
1004
+ $ref: ../components/schemas/common.yaml#/ResourceId
1005
+ - name: status
1006
+ in: query
1007
+ required: false
1008
+ description: Filter by question status, or `all` (the default).
1009
+ schema:
1010
+ default: all
1011
+ anyOf:
1012
+ - $ref: ../components/schemas/ops.yaml#/OpsQuestionStatus
1013
+ - type: string
1014
+ const: all
1015
+ responses:
1016
+ "200":
1017
+ description: List an item's questions
1018
+ content:
1019
+ application/json:
1020
+ schema:
1021
+ $ref: ../components/schemas/ops.yaml#/ListOpsQuestionsResponse
1022
+ "400":
1023
+ $ref: ../components/responses.yaml#/BadRequest
1024
+ "401":
1025
+ $ref: ../components/responses.yaml#/Unauthorized
1026
+ "403":
1027
+ $ref: ../components/responses.yaml#/Forbidden
1028
+ "404":
1029
+ $ref: ../components/responses.yaml#/NotFound
1030
+ "422":
1031
+ $ref: ../components/responses.yaml#/UnprocessableEntity
1032
+ x-error-codes:
1033
+ - BAD_REQUEST
1034
+ - UNAUTHORIZED
1035
+ - FORBIDDEN
1036
+ - NOT_FOUND
1037
+ x-cli:
1038
+ name: list
1039
+ positional:
1040
+ - handle
1041
+ post:
1042
+ operationId: askOpsQuestions
1043
+ summary: Ask the team questions about an item
1044
+ description: |-
1045
+ Ask 1–4 structured questions about a queue item — the way to get a
1046
+ decision from a person when the implementation needs one. Each question
1047
+ is the `AskUserQuestion` shape: a short `header` chip, the full
1048
+ `question`, 2–4 `options` (`label` + `description`), and `multiSelect`
1049
+ (checkboxes instead of radios). The person can always answer "Other" in
1050
+ free text, so never add an "Other" option yourself. The questions render
1051
+ at the very top of the item's detail panel and mark the row in the queue.
1052
+
1053
+ **Delivery.** `resume` re-fires your trigger-connector run on the item
1054
+ once every question it asked is answered, continuing the same run record
1055
+ with the answers in the prompt — stop after asking. `poll` fires nothing;
1056
+ poll `GET .../questions` instead. Omitted, it is `resume` when `runId`
1057
+ names a run launched through a trigger connector, else `poll`.
1058
+
1059
+ **Use case:** Blocked on a product decision (which behaviour to keep,
1060
+ which of two fixes to ship) — ask instead of guessing, then wait for the
1061
+ answer.
1062
+ tags:
1063
+ - Questions
1064
+ parameters:
1065
+ - $ref: ../components/parameters.yaml#/ProjectId
1066
+ - name: handle
1067
+ in: path
1068
+ required: true
1069
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1070
+ schema:
1071
+ $ref: ../components/schemas/common.yaml#/ResourceId
1072
+ requestBody:
1073
+ required: true
1074
+ content:
1075
+ application/json:
1076
+ schema:
1077
+ $ref: ../components/schemas/ops.yaml#/AskOpsQuestionsRequest
1078
+ examples:
1079
+ single:
1080
+ summary: Ask one radio question
1081
+ value:
1082
+ runId: 0d3f4c8e-7a51-4c2e-9b1f-1e2d3c4b5a69
1083
+ questions:
1084
+ - header: Legacy param
1085
+ question: Should the fix keep honouring the legacy `?v=1` query param?
1086
+ multiSelect: false
1087
+ options:
1088
+ - label: Keep it
1089
+ description: Old links keep working; the redirect stays
1090
+ - label: Drop it
1091
+ description: Simpler code; old links land on the default view
1092
+ responses:
1093
+ "200":
1094
+ description: The created questions, in the order asked
1095
+ content:
1096
+ application/json:
1097
+ schema:
1098
+ $ref: ../components/schemas/ops.yaml#/AskOpsQuestionsResponse
1099
+ "400":
1100
+ $ref: ../components/responses.yaml#/BadRequest
1101
+ "401":
1102
+ $ref: ../components/responses.yaml#/Unauthorized
1103
+ "403":
1104
+ $ref: ../components/responses.yaml#/Forbidden
1105
+ "404":
1106
+ $ref: ../components/responses.yaml#/NotFound
1107
+ "422":
1108
+ $ref: ../components/responses.yaml#/UnprocessableEntity
1109
+ x-error-codes:
1110
+ - BAD_REQUEST
1111
+ - UNAUTHORIZED
1112
+ - FORBIDDEN
1113
+ - NOT_FOUND
1114
+ - VALIDATION
1115
+ x-cli:
1116
+ name: ask
1117
+ positional:
1118
+ - handle
1119
+ /api/admin/ops/{handle}/questions/{questionId}/answer:
1120
+ post:
1121
+ operationId: answerOpsQuestion
1122
+ summary: Answer a question
1123
+ description: |-
1124
+ Answer one open question on a queue item — pick option labels in
1125
+ `selected` (exactly one unless the question is `multiSelect`) and/or
1126
+ write a free-text `other`. The question moves to `completed`. When it was
1127
+ the last open question of a `resume` run, that agent is re-fired on the
1128
+ item with every answer. A person's action: never allow-listed for
1129
+ restricted ops keys.
1130
+
1131
+ **Use case:** Unblock an agent from the CLI instead of the dashboard.
1132
+ tags:
1133
+ - Questions
1134
+ parameters:
1135
+ - $ref: ../components/parameters.yaml#/ProjectId
1136
+ - name: handle
1137
+ in: path
1138
+ required: true
1139
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1140
+ schema:
1141
+ $ref: ../components/schemas/common.yaml#/ResourceId
1142
+ - name: questionId
1143
+ in: path
1144
+ required: true
1145
+ description: The question id (from `ask` or `list`).
1146
+ schema:
1147
+ $ref: ../components/schemas/common.yaml#/ResourceId
1148
+ requestBody:
1149
+ required: true
1150
+ content:
1151
+ application/json:
1152
+ schema:
1153
+ $ref: ../components/schemas/ops.yaml#/AnswerOpsQuestionRequest
1154
+ examples:
1155
+ option:
1156
+ summary: Pick an option
1157
+ value:
1158
+ selected:
1159
+ - Keep it
1160
+ other:
1161
+ summary: Answer in free text
1162
+ value:
1163
+ other: Keep it for a release, then drop it
1164
+ responses:
1165
+ "200":
1166
+ description: The answered question
1167
+ content:
1168
+ application/json:
1169
+ schema:
1170
+ $ref: ../components/schemas/ops.yaml#/OpsQuestion
1171
+ "400":
1172
+ $ref: ../components/responses.yaml#/BadRequest
1173
+ "401":
1174
+ $ref: ../components/responses.yaml#/Unauthorized
1175
+ "403":
1176
+ $ref: ../components/responses.yaml#/Forbidden
1177
+ "404":
1178
+ $ref: ../components/responses.yaml#/NotFound
1179
+ "409":
1180
+ $ref: ../components/responses.yaml#/Conflict
1181
+ "422":
1182
+ $ref: ../components/responses.yaml#/UnprocessableEntity
1183
+ x-error-codes:
1184
+ - BAD_REQUEST
1185
+ - UNAUTHORIZED
1186
+ - FORBIDDEN
1187
+ - NOT_FOUND
1188
+ - INVALID_TRANSITION
1189
+ - VALIDATION
1190
+ x-cli:
1191
+ name: answer
1192
+ positional:
1193
+ - handle
1194
+ - questionId
1195
+ /api/admin/ops/{handle}/questions/{questionId}/cancel:
1196
+ post:
1197
+ operationId: cancelOpsQuestion
1198
+ summary: Withdraw a question
1199
+ description: |-
1200
+ Withdraw one open question you asked — it no longer needs an answer
1201
+ (you found it out yourself, or the item moved on). The question moves to
1202
+ `cancelled` and leaves the detail panel. Withdrawing the last open
1203
+ question of a run delivers nothing.
1204
+
1205
+ **Use case:** You asked, then answered it yourself from the code — take
1206
+ it off the person's plate.
1207
+ tags:
1208
+ - Questions
1209
+ parameters:
1210
+ - $ref: ../components/parameters.yaml#/ProjectId
1211
+ - name: handle
1212
+ in: path
1213
+ required: true
1214
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1215
+ schema:
1216
+ $ref: ../components/schemas/common.yaml#/ResourceId
1217
+ - name: questionId
1218
+ in: path
1219
+ required: true
1220
+ description: The question id (from `ask` or `list`).
1221
+ schema:
1222
+ $ref: ../components/schemas/common.yaml#/ResourceId
1223
+ responses:
1224
+ "200":
1225
+ description: The withdrawn question
1226
+ content:
1227
+ application/json:
1228
+ schema:
1229
+ $ref: ../components/schemas/ops.yaml#/OpsQuestion
1230
+ "400":
1231
+ $ref: ../components/responses.yaml#/BadRequest
1232
+ "401":
1233
+ $ref: ../components/responses.yaml#/Unauthorized
1234
+ "403":
1235
+ $ref: ../components/responses.yaml#/Forbidden
1236
+ "404":
1237
+ $ref: ../components/responses.yaml#/NotFound
1238
+ "409":
1239
+ $ref: ../components/responses.yaml#/Conflict
1240
+ x-error-codes:
1241
+ - BAD_REQUEST
1242
+ - UNAUTHORIZED
1243
+ - FORBIDDEN
1244
+ - NOT_FOUND
1245
+ - INVALID_TRANSITION
1246
+ x-cli:
1247
+ name: cancel
1248
+ positional:
1249
+ - handle
1250
+ - questionId
1251
+ /api/admin/ops/{handle}/qa-notes:
1252
+ get:
1253
+ operationId: listOpsQaNotes
1254
+ summary: List an item's QA notes
1255
+ description: |-
1256
+ The typed QA notes on a queue item, newest first (max 200) — narrowing,
1257
+ clarification, verification and correction notes, each with its author and
1258
+ time. They are separate from the comment thread: read these to learn the
1259
+ CURRENT QA state of a ticket (what remains failing, what "fixed" now means,
1260
+ the last verification verdict) without parsing prose comments.
1261
+
1262
+ **Use case:** A coding agent picks an item up and checks the latest
1263
+ `verification` verdict and any `narrowing` note before touching the code.
1264
+ tags:
1265
+ - QA notes
1266
+ parameters:
1267
+ - $ref: ../components/parameters.yaml#/ProjectId
1268
+ - name: handle
1269
+ in: path
1270
+ required: true
1271
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1272
+ schema:
1273
+ $ref: ../components/schemas/common.yaml#/ResourceId
1274
+ - name: kind
1275
+ in: query
1276
+ required: false
1277
+ description: Only notes of this kind.
1278
+ schema:
1279
+ $ref: ../components/schemas/ops.yaml#/OpsQaNoteKind
1280
+ responses:
1281
+ "200":
1282
+ description: List an item's QA notes
1283
+ content:
1284
+ application/json:
1285
+ schema:
1286
+ $ref: ../components/schemas/ops.yaml#/ListOpsQaNotesResponse
1287
+ "400":
1288
+ $ref: ../components/responses.yaml#/BadRequest
1289
+ "401":
1290
+ $ref: ../components/responses.yaml#/Unauthorized
1291
+ "403":
1292
+ $ref: ../components/responses.yaml#/Forbidden
1293
+ "404":
1294
+ $ref: ../components/responses.yaml#/NotFound
1295
+ "422":
1296
+ $ref: ../components/responses.yaml#/UnprocessableEntity
1297
+ x-error-codes:
1298
+ - BAD_REQUEST
1299
+ - UNAUTHORIZED
1300
+ - FORBIDDEN
1301
+ - NOT_FOUND
1302
+ x-cli:
1303
+ name: list
1304
+ positional:
1305
+ - handle
1306
+ post:
1307
+ operationId: createOpsQaNote
1308
+ summary: Add a QA note to an item
1309
+ description: |-
1310
+ Append one typed QA note to a queue item. `kind` is `narrowing` (what now
1311
+ passes vs what still fails), `clarification` (what "fixed" now means),
1312
+ `verification` (requires a `verdict` of `pass` or `fail`, and `body` says
1313
+ what was checked) or `correction` (withdraws an earlier framing). Notes
1314
+ are append-only and appear in the item's QA notes section, not in the
1315
+ comment thread. The author is the caller's identity; pass `agent` to
1316
+ record the note as written by that agent type's QA automation. A `fail` verdict never changes the item's
1317
+ status by itself: the dashboard offers an explicit "Reopen item" action,
1318
+ and `ops update --status open` does the same from the CLI.
1319
+
1320
+ **Use case:** QA automation records "verified on production: FAIL, the
1321
+ second facet still errors" as data an agent can read back.
1322
+ tags:
1323
+ - QA notes
1324
+ parameters:
1325
+ - $ref: ../components/parameters.yaml#/ProjectId
1326
+ - name: handle
1327
+ in: path
1328
+ required: true
1329
+ description: Per-project item number (e.g. `7`) or the full ops item id.
1330
+ schema:
1331
+ $ref: ../components/schemas/common.yaml#/ResourceId
1332
+ requestBody:
1333
+ required: true
1334
+ content:
1335
+ application/json:
1336
+ schema:
1337
+ $ref: ../components/schemas/ops.yaml#/CreateOpsQaNoteRequest
1338
+ examples:
1339
+ verification:
1340
+ summary: A failing verification
1341
+ value:
1342
+ kind: verification
1343
+ verdict: fail
1344
+ body: Retested on production after the deploy — the export still drops the second sheet
1345
+ narrowing:
1346
+ summary: Narrow a bug to the facet that still fails
1347
+ value:
1348
+ kind: narrowing
1349
+ body: The list view is fixed; only the detail panel still shows the stale count
1350
+ responses:
1351
+ "200":
1352
+ description: The created note
1353
+ content:
1354
+ application/json:
1355
+ schema:
1356
+ $ref: ../components/schemas/ops.yaml#/OpsQaNote
1357
+ "400":
1358
+ $ref: ../components/responses.yaml#/BadRequest
1359
+ "401":
1360
+ $ref: ../components/responses.yaml#/Unauthorized
1361
+ "403":
1362
+ $ref: ../components/responses.yaml#/Forbidden
1363
+ "404":
1364
+ $ref: ../components/responses.yaml#/NotFound
1365
+ "422":
1366
+ $ref: ../components/responses.yaml#/UnprocessableEntity
1367
+ x-error-codes:
1368
+ - BAD_REQUEST
1369
+ - UNAUTHORIZED
1370
+ - FORBIDDEN
1371
+ - NOT_FOUND
1372
+ - VALIDATION
1373
+ x-cli:
1374
+ name: create
1375
+ positional:
1376
+ - handle
874
1377
  /api/admin/agent-profiles:
875
1378
  get:
876
1379
  operationId: listOpsAgents