monday-cli 0.3.0 → 0.5.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 (198) hide show
  1. package/CHANGELOG.md +719 -0
  2. package/README.md +208 -36
  3. package/dist/api/assets.d.ts +326 -0
  4. package/dist/api/assets.d.ts.map +1 -0
  5. package/dist/api/assets.js +519 -0
  6. package/dist/api/assets.js.map +1 -0
  7. package/dist/api/column-types.d.ts +13 -7
  8. package/dist/api/column-types.d.ts.map +1 -1
  9. package/dist/api/column-types.js +7 -3
  10. package/dist/api/column-types.js.map +1 -1
  11. package/dist/api/column-values.d.ts +8 -1
  12. package/dist/api/column-values.d.ts.map +1 -1
  13. package/dist/api/column-values.js +16 -6
  14. package/dist/api/column-values.js.map +1 -1
  15. package/dist/api/documents.d.ts +1652 -0
  16. package/dist/api/documents.d.ts.map +1 -0
  17. package/dist/api/documents.js +2411 -0
  18. package/dist/api/documents.js.map +1 -0
  19. package/dist/api/item-watch.d.ts +263 -0
  20. package/dist/api/item-watch.d.ts.map +1 -0
  21. package/dist/api/item-watch.js +709 -0
  22. package/dist/api/item-watch.js.map +1 -0
  23. package/dist/api/multipart-transport.d.ts +223 -0
  24. package/dist/api/multipart-transport.d.ts.map +1 -0
  25. package/dist/api/multipart-transport.js +274 -0
  26. package/dist/api/multipart-transport.js.map +1 -0
  27. package/dist/api/parallel-dispatch.d.ts +155 -0
  28. package/dist/api/parallel-dispatch.d.ts.map +1 -0
  29. package/dist/api/parallel-dispatch.js +243 -0
  30. package/dist/api/parallel-dispatch.js.map +1 -0
  31. package/dist/api/partial-success-bulk.d.ts +118 -60
  32. package/dist/api/partial-success-bulk.d.ts.map +1 -1
  33. package/dist/api/partial-success-bulk.js +137 -79
  34. package/dist/api/partial-success-bulk.js.map +1 -1
  35. package/dist/api/partial-success-mutation.d.ts +13 -1
  36. package/dist/api/partial-success-mutation.d.ts.map +1 -1
  37. package/dist/api/partial-success-mutation.js +5 -1
  38. package/dist/api/partial-success-mutation.js.map +1 -1
  39. package/dist/api/raw-write.d.ts +13 -4
  40. package/dist/api/raw-write.d.ts.map +1 -1
  41. package/dist/api/raw-write.js +22 -11
  42. package/dist/api/raw-write.js.map +1 -1
  43. package/dist/api/resolve-client.d.ts +11 -0
  44. package/dist/api/resolve-client.d.ts.map +1 -1
  45. package/dist/api/resolve-client.js +9 -1
  46. package/dist/api/resolve-client.js.map +1 -1
  47. package/dist/api/teams.d.ts +657 -0
  48. package/dist/api/teams.d.ts.map +1 -0
  49. package/dist/api/teams.js +880 -0
  50. package/dist/api/teams.js.map +1 -0
  51. package/dist/cli/run.d.ts +20 -0
  52. package/dist/cli/run.d.ts.map +1 -1
  53. package/dist/cli/run.js +1 -0
  54. package/dist/cli/run.js.map +1 -1
  55. package/dist/commands/board/column-create.d.ts +6 -5
  56. package/dist/commands/board/column-create.d.ts.map +1 -1
  57. package/dist/commands/board/column-create.js +9 -6
  58. package/dist/commands/board/column-create.js.map +1 -1
  59. package/dist/commands/completion.d.ts +188 -0
  60. package/dist/commands/completion.d.ts.map +1 -0
  61. package/dist/commands/completion.js +418 -0
  62. package/dist/commands/completion.js.map +1 -0
  63. package/dist/commands/doc/append-markdown.d.ts +117 -0
  64. package/dist/commands/doc/append-markdown.d.ts.map +1 -0
  65. package/dist/commands/doc/append-markdown.js +253 -0
  66. package/dist/commands/doc/append-markdown.js.map +1 -0
  67. package/dist/commands/doc/block-create.d.ts +114 -0
  68. package/dist/commands/doc/block-create.d.ts.map +1 -0
  69. package/dist/commands/doc/block-create.js +206 -0
  70. package/dist/commands/doc/block-create.js.map +1 -0
  71. package/dist/commands/doc/block-delete.d.ts +72 -0
  72. package/dist/commands/doc/block-delete.d.ts.map +1 -0
  73. package/dist/commands/doc/block-delete.js +161 -0
  74. package/dist/commands/doc/block-delete.js.map +1 -0
  75. package/dist/commands/doc/block-update.d.ts +75 -0
  76. package/dist/commands/doc/block-update.d.ts.map +1 -0
  77. package/dist/commands/doc/block-update.js +162 -0
  78. package/dist/commands/doc/block-update.js.map +1 -0
  79. package/dist/commands/doc/create-in-workspace.d.ts +76 -0
  80. package/dist/commands/doc/create-in-workspace.d.ts.map +1 -0
  81. package/dist/commands/doc/create-in-workspace.js +164 -0
  82. package/dist/commands/doc/create-in-workspace.js.map +1 -0
  83. package/dist/commands/doc/create-on-column.d.ts +71 -0
  84. package/dist/commands/doc/create-on-column.d.ts.map +1 -0
  85. package/dist/commands/doc/create-on-column.js +146 -0
  86. package/dist/commands/doc/create-on-column.js.map +1 -0
  87. package/dist/commands/doc/delete.d.ts +68 -0
  88. package/dist/commands/doc/delete.d.ts.map +1 -0
  89. package/dist/commands/doc/delete.js +146 -0
  90. package/dist/commands/doc/delete.js.map +1 -0
  91. package/dist/commands/doc/duplicate.d.ts +101 -0
  92. package/dist/commands/doc/duplicate.d.ts.map +1 -0
  93. package/dist/commands/doc/duplicate.js +191 -0
  94. package/dist/commands/doc/duplicate.js.map +1 -0
  95. package/dist/commands/doc/get.d.ts +46 -0
  96. package/dist/commands/doc/get.d.ts.map +1 -0
  97. package/dist/commands/doc/get.js +95 -0
  98. package/dist/commands/doc/get.js.map +1 -0
  99. package/dist/commands/doc/import-html.d.ts +125 -0
  100. package/dist/commands/doc/import-html.d.ts.map +1 -0
  101. package/dist/commands/doc/import-html.js +273 -0
  102. package/dist/commands/doc/import-html.js.map +1 -0
  103. package/dist/commands/doc/list.d.ts +86 -0
  104. package/dist/commands/doc/list.d.ts.map +1 -0
  105. package/dist/commands/doc/list.js +217 -0
  106. package/dist/commands/doc/list.js.map +1 -0
  107. package/dist/commands/doc/rename.d.ts +60 -0
  108. package/dist/commands/doc/rename.d.ts.map +1 -0
  109. package/dist/commands/doc/rename.js +135 -0
  110. package/dist/commands/doc/rename.js.map +1 -0
  111. package/dist/commands/index.d.ts.map +1 -1
  112. package/dist/commands/index.js +162 -0
  113. package/dist/commands/index.js.map +1 -1
  114. package/dist/commands/item/create.js +2 -2
  115. package/dist/commands/item/update.d.ts +1 -0
  116. package/dist/commands/item/update.d.ts.map +1 -1
  117. package/dist/commands/item/update.js +61 -0
  118. package/dist/commands/item/update.js.map +1 -1
  119. package/dist/commands/item/upload.d.ts +108 -0
  120. package/dist/commands/item/upload.d.ts.map +1 -0
  121. package/dist/commands/item/upload.js +370 -0
  122. package/dist/commands/item/upload.js.map +1 -0
  123. package/dist/commands/item/watch.d.ts +90 -0
  124. package/dist/commands/item/watch.d.ts.map +1 -0
  125. package/dist/commands/item/watch.js +342 -0
  126. package/dist/commands/item/watch.js.map +1 -0
  127. package/dist/commands/update/create.d.ts.map +1 -1
  128. package/dist/commands/update/create.js +6 -4
  129. package/dist/commands/update/create.js.map +1 -1
  130. package/dist/commands/update/edit.d.ts +4 -2
  131. package/dist/commands/update/edit.d.ts.map +1 -1
  132. package/dist/commands/update/edit.js +10 -6
  133. package/dist/commands/update/edit.js.map +1 -1
  134. package/dist/commands/update/reply.d.ts +4 -2
  135. package/dist/commands/update/reply.d.ts.map +1 -1
  136. package/dist/commands/update/reply.js +10 -6
  137. package/dist/commands/update/reply.js.map +1 -1
  138. package/dist/commands/update/upload.d.ts +69 -0
  139. package/dist/commands/update/upload.d.ts.map +1 -0
  140. package/dist/commands/update/upload.js +235 -0
  141. package/dist/commands/update/upload.js.map +1 -0
  142. package/dist/commands/user/_team-membership.d.ts +10 -0
  143. package/dist/commands/user/_team-membership.d.ts.map +1 -0
  144. package/dist/commands/user/_team-membership.js +88 -0
  145. package/dist/commands/user/_team-membership.js.map +1 -0
  146. package/dist/commands/user/team-add-members.d.ts +81 -0
  147. package/dist/commands/user/team-add-members.d.ts.map +1 -0
  148. package/dist/commands/user/team-add-members.js +186 -0
  149. package/dist/commands/user/team-add-members.js.map +1 -0
  150. package/dist/commands/user/team-create.d.ts +82 -0
  151. package/dist/commands/user/team-create.d.ts.map +1 -0
  152. package/dist/commands/user/team-create.js +206 -0
  153. package/dist/commands/user/team-create.js.map +1 -0
  154. package/dist/commands/user/team-delete.d.ts +56 -0
  155. package/dist/commands/user/team-delete.d.ts.map +1 -0
  156. package/dist/commands/user/team-delete.js +137 -0
  157. package/dist/commands/user/team-delete.js.map +1 -0
  158. package/dist/commands/user/team-get.d.ts +41 -0
  159. package/dist/commands/user/team-get.d.ts.map +1 -0
  160. package/dist/commands/user/team-get.js +87 -0
  161. package/dist/commands/user/team-get.js.map +1 -0
  162. package/dist/commands/user/team-list.d.ts +39 -0
  163. package/dist/commands/user/team-list.d.ts.map +1 -0
  164. package/dist/commands/user/team-list.js +90 -0
  165. package/dist/commands/user/team-list.js.map +1 -0
  166. package/dist/commands/user/team-remove-members.d.ts +71 -0
  167. package/dist/commands/user/team-remove-members.d.ts.map +1 -0
  168. package/dist/commands/user/team-remove-members.js +176 -0
  169. package/dist/commands/user/team-remove-members.js.map +1 -0
  170. package/dist/types/ids.d.ts +8 -0
  171. package/dist/types/ids.d.ts.map +1 -1
  172. package/dist/types/ids.js +53 -5
  173. package/dist/types/ids.js.map +1 -1
  174. package/dist/utils/mime.d.ts +24 -0
  175. package/dist/utils/mime.d.ts.map +1 -0
  176. package/dist/utils/mime.js +64 -0
  177. package/dist/utils/mime.js.map +1 -0
  178. package/dist/utils/output/envelope.d.ts +30 -0
  179. package/dist/utils/output/envelope.d.ts.map +1 -1
  180. package/dist/utils/output/envelope.js +26 -0
  181. package/dist/utils/output/envelope.js.map +1 -1
  182. package/dist/utils/output/ndjson.d.ts +25 -0
  183. package/dist/utils/output/ndjson.d.ts.map +1 -1
  184. package/dist/utils/output/ndjson.js +12 -0
  185. package/dist/utils/output/ndjson.js.map +1 -1
  186. package/dist/utils/parse-brand-list.d.ts +95 -0
  187. package/dist/utils/parse-brand-list.d.ts.map +1 -0
  188. package/dist/utils/parse-brand-list.js +96 -0
  189. package/dist/utils/parse-brand-list.js.map +1 -0
  190. package/dist/utils/signal.d.ts +42 -0
  191. package/dist/utils/signal.d.ts.map +1 -0
  192. package/dist/utils/signal.js +45 -0
  193. package/dist/utils/signal.js.map +1 -0
  194. package/dist/utils/source-content.d.ts +93 -0
  195. package/dist/utils/source-content.d.ts.map +1 -0
  196. package/dist/utils/source-content.js +120 -0
  197. package/dist/utils/source-content.js.map +1 -0
  198. package/package.json +1 -1
@@ -3,18 +3,20 @@
3
3
  * `item update --continue-on-error` flag (`cli-design.md` §6.4
4
4
  * "Bulk per-item partial-success" sub-section).
5
5
  *
6
- * **What this module owns.** A thin wrapper around
7
- * {@link dispatchSequential} from
8
- * `src/api/partial-success-mutation.ts` that drives the matched-
6
+ * **What this module owns.** A thin wrapper around the selected
7
+ * per-target dispatcher — {@link dispatchSequential} from
8
+ * `src/api/partial-success-mutation.ts` (default / M25 path) OR
9
+ * {@link dispatchParallel} from `src/api/parallel-dispatch.ts`
10
+ * (v0.4-M30 `--concurrency > 1` path) — that drives the matched-
9
11
  * item-ID list through one wire call per item, capturing per-
10
12
  * item failures into the result records rather than aborting
11
13
  * the loop. The wrapper sits BETWEEN the bulk command-action
12
14
  * orchestrator (`src/commands/item/update.ts:runBulk`) and the
13
- * shared `dispatchSequential` helper — the action body owns the
14
- * matched-item-walk + column-resolution pre-pass + confirmation
15
- * gate, then hands the resolved `SelectedMutation` + matched-
16
- * item IDs to this wrapper, which fans them out + projects the
17
- * partial-success envelope's `data.results[]` records.
15
+ * shared dispatcher — the action body owns the matched-item-
16
+ * walk + column-resolution pre-pass + confirmation gate, then
17
+ * hands the resolved `SelectedMutation` + matched-item IDs to
18
+ * this wrapper, which fans them out + projects the partial-
19
+ * success envelope's `data.results[]` records.
18
20
  *
19
21
  * **Why a separate module rather than folding into update.ts.**
20
22
  * Three reasons:
@@ -65,16 +67,31 @@
65
67
  * 3-consumer trigger: single-item + fail-fast bulk + M25
66
68
  * partial-success bulk).
67
69
  *
68
- * **Per-item dispatch wiring.** Runtime body loops
69
- * {@link dispatchSequential} over `matchedItemIds` with
70
- * id-field `'item_id'`. The per-item dispatch callback fires
71
- * one `executeItemMutation` call. Successes populate
72
- * `results[i].item` with the `ProjectedItem` via a side-map
73
- * fold; failures land in `results[i].error: {code, message}`
74
- * via `dispatchSequential`'s built-in error decoration.
75
- * `internal_error` codes re-throw as whole-call (M14 round-2
76
- * F1 precedentschema-drift in the response MUST NOT be
77
- * papered over as a per-item failure).
70
+ * **v0.4-M30 extension.** Adds the `concurrency` input slot +
71
+ * the routing branch to {@link dispatchParallel} (new module
72
+ * `src/api/parallel-dispatch.ts` runtime body landed at M30
73
+ * IMPL). When the caller passes `concurrency > 1`, the runtime
74
+ * fans out per-target dispatches via a bounded async-pool;
75
+ * absent or `concurrency === 1` preserves the M25 sequential
76
+ * path verbatim. The per-target dispatch closure is hoisted to
77
+ * a named local so both routes share the same
78
+ * `executeItemMutation` + `foldAndRemap` body keeps the
79
+ * R-NEW-28 6-axis behavioral-equivalence audit straightforward.
80
+ * The M30 IMPL also threads an optional `signal?: AbortSignal`
81
+ * through both dispatchers (axis-6 scheduler short-circuit).
82
+ *
83
+ * **Per-item dispatch wiring.** Runtime body routes between
84
+ * {@link dispatchSequential} (default — `concurrency` absent /
85
+ * `=== 1`) and {@link dispatchParallel} (v0.4-M30 —
86
+ * `concurrency > 1`) over `matchedItemIds` with id-field
87
+ * `'item_id'`. The per-target dispatch callback (shared between
88
+ * routes verbatim) fires one `executeItemMutation` call.
89
+ * Successes populate `results[i].item` with the `ProjectedItem`
90
+ * via a side-map fold; failures land in
91
+ * `results[i].error: {code, message}` via the dispatcher's
92
+ * built-in error decoration. `internal_error` codes re-throw
93
+ * as whole-call (M14 round-2 F1 precedent — schema-drift in
94
+ * the response MUST NOT be papered over as a per-item failure).
78
95
  *
79
96
  * **`data.summary.failed_count` invariant.** The action body
80
97
  * derives `failed_count` from the result records
@@ -103,13 +120,15 @@ import type { EnvelopeSource } from './source-aggregator.js';
103
120
  * The `item` slot on success records is the §6.2 `ProjectedItem`
104
121
  * shape (same projection single-item `item update` emits as
105
122
  * `data`). The `error` slot on failure records carries
106
- * `{code, message}` populated from
107
- * `dispatchSequential`'s per-target error decoration.
123
+ * `{code, message}` populated from the selected dispatcher's
124
+ * per-target error decoration (`dispatchSequential` or
125
+ * `dispatchParallel` — same shape per the R-NEW-28 axis-1
126
+ * equivalence).
108
127
  *
109
- * `z.discriminatedUnion` would be the natural shape but
110
- * `dispatchSequential`'s result records carry a dynamic
111
- * id-field key (`{item_id: ..., ok, error?}`) — modelling that
112
- * as a per-record union complicates the schema and downstream
128
+ * `z.discriminatedUnion` would be the natural shape but the
129
+ * dispatchers' result records carry a dynamic id-field key
130
+ * (`{item_id: ..., ok, error?}`) — modelling that as a
131
+ * per-record union complicates the schema and downstream
113
132
  * consumers' type-narrowing. The flatter shape below carries
114
133
  * `item` + `error` as optionals; the action body's projection
115
134
  * + the wrapper's per-item dispatch enforce the
@@ -234,7 +253,9 @@ export type PartialSuccessBulkUpdateData = z.infer<typeof partialSuccessBulkUpda
234
253
  * applies — a stale-cache `validation_failed` remaps to the
235
254
  * stable `column_archived` code agents key off (cli-design
236
255
  * §6.5). The wrapper's per-item dispatch callback fires
237
- * `foldAndRemap` BEFORE throwing into `dispatchSequential` so
256
+ * `foldAndRemap` BEFORE throwing into the selected dispatcher
257
+ * (`dispatchSequential` or `dispatchParallel` — both apply
258
+ * the same per-target error decoration) so
238
259
  * the per-record `error.code` in `data.results[]` matches the
239
260
  * shape the fail-fast path would have surfaced as the
240
261
  * top-level `error.code`. That requires the same context the
@@ -283,15 +304,39 @@ export interface RunPartialSuccessBulkUpdateInputs {
283
304
  readonly env: NodeJS.ProcessEnv;
284
305
  readonly noCache: boolean;
285
306
  readonly resolutionSource: 'live' | 'cache' | 'mixed';
307
+ /**
308
+ * v0.4-M30 `--concurrency <N>` argv slot (cli-design §9.3 +
309
+ * §6.4 "Bulk per-item partial-success — Parallel dispatch").
310
+ * `undefined` or `1` routes through `dispatchSequential`
311
+ * (byte-equivalent to the v0.3-M25 path); `> 1` routes
312
+ * through {@link dispatchParallel} (bounded async-pool).
313
+ * Action layer's argv parser pins the value to
314
+ * `[MIN_CONCURRENCY, MAX_CONCURRENCY]` (1..32) before reaching
315
+ * this helper.
316
+ */
317
+ readonly concurrency: number | undefined;
318
+ /**
319
+ * v0.4-M30 SIGINT / abort threading. When the runner aborts
320
+ * `ctx.signal`, both dispatchers check `signal.aborted` at the
321
+ * iteration / worker-loop boundary and re-throw the signal's
322
+ * reason whole-call (mirrors {@link dispatchParallel} axis-6).
323
+ * In-flight wire calls abort via the existing
324
+ * `MondayClient.signal` configured at construction time
325
+ * (the client threads its signal into every fetch). Optional
326
+ * — omitting it preserves v0.3-M25 behaviour exactly for
327
+ * callers that don't need cooperative abort.
328
+ */
329
+ readonly signal?: AbortSignal;
286
330
  }
287
331
  /**
288
332
  * Result returned by {@link runPartialSuccessBulkUpdate} to the
289
333
  * action layer.
290
334
  *
291
335
  * - `results` — the array of per-item records the helper built
292
- * via `dispatchSequential` + the per-item projection
293
- * callback. Direct mirror of `data.results[]` in the §6.4
294
- * envelope. **Mutable array** so the action layer can pass
336
+ * via the selected dispatcher (`dispatchSequential` or
337
+ * `dispatchParallel`) + the per-item projection callback.
338
+ * Direct mirror of `data.results[]` in the §6.4 envelope.
339
+ * **Mutable array** so the action layer can pass
295
340
  * it directly to `partialSuccessBulkUpdateDataSchema.parse`
296
341
  * (zod's `z.array(...)` infers a mutable array — wrapping
297
342
  * `readonly` would force a spread at the call site).
@@ -326,19 +371,24 @@ export declare const PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE: EnvelopeSource;
326
371
  /**
327
372
  * Drives the per-item dispatch loop under `--continue-on-error`.
328
373
  *
329
- * Implementation (M25 impl `78889df` refactor + this commit):
374
+ * Implementation (M25 impl `78889df` refactor + this commit;
375
+ * extended at v0.4-M30 pre-flight with the `concurrency` routing
376
+ * branch):
330
377
  *
331
- * 1. Loop {@link dispatchSequential} over `matchedItemIds`
332
- * with id-field `'item_id'`.
378
+ * 1. Loop {@link dispatchSequential} (default / M25 path) OR
379
+ * {@link dispatchParallel} (v0.4-M30 `--concurrency > 1`
380
+ * path; runtime body landed at M30 IMPL) over
381
+ * `matchedItemIds` with id-field `'item_id'`.
333
382
  * 2. Per-item dispatch callback fires
334
383
  * {@link executeItemMutation} against the resolved
335
384
  * `SelectedMutation`. On a {@link MondayCliError} catch,
336
385
  * run {@link foldAndRemap} with `resolverWarnings` +
337
386
  * `remapColumnIds` + `env` + `noCache` + `resolutionSource`
338
- * from the inputs BEFORE re-throwing into
339
- * `dispatchSequential`. This makes the per-record
340
- * `error.code` in `data.results[]` carry the SAME stable
341
- * code (`column_archived` after a stale-cache
387
+ * from the inputs BEFORE re-throwing into the selected
388
+ * dispatcher (`dispatchSequential` or `dispatchParallel`).
389
+ * This makes the per-record `error.code` in
390
+ * `data.results[]` carry the SAME stable code
391
+ * (`column_archived` after a stale-cache
342
392
  * `validation_failed` remap) that the v0.1 fail-fast
343
393
  * path would have surfaced at the top level — Codex
344
394
  * round-1 P1-1 contract requirement (cli-design §6.5
@@ -346,52 +396,60 @@ export declare const PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE: EnvelopeSource;
346
396
  * fail-modes).
347
397
  * 3. On success, capture the `ProjectedItem` into a side
348
398
  * map keyed by `item_id`.
349
- * 4. After the loop, walk the `dispatchSequential` results
350
- * and fold the per-item `ProjectedItem` from the side
399
+ * 4. After the loop, walk the result rows (from whichever
400
+ * dispatcher fired `dispatchSequential` by default;
401
+ * {@link dispatchParallel} when `concurrency > 1`) and
402
+ * fold the per-item `ProjectedItem` from the side
351
403
  * map into each `results[i].item` slot via
352
404
  * {@link foldPartialSuccessBulkResult}. Failure records
353
405
  * already carry `error: {code, message}` (with the
354
- * foldAndRemap-applied code) via
355
- * `dispatchSequential`'s built-in error decoration.
406
+ * foldAndRemap-applied code) via the dispatcher's built-in
407
+ * error decoration (both routes share the same per-target
408
+ * error capture contract).
356
409
  * 5. Return `{results}` — the action layer folds the
357
410
  * constant `'live'` dispatch source via
358
411
  * `sourceAgg.record(PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE,
359
412
  * null)` and emits the envelope.
360
413
  *
361
414
  * **`internal_error` re-throw escape hatch.** Per M14 round-2
362
- * F1 / round-3 F1, `dispatchSequential` re-throws
363
- * `internal_error` so schema-drift in the response surfaces
364
- * as whole-call (top-level `ok: false`) rather than per-record
365
- * — papering over `internal_error` would hide the malformed-
366
- * response signal agents need to know about. The M25 wrapper
367
- * inherits this behaviour by NOT wrapping the
368
- * `dispatchSequential` re-throw `foldAndRemap` only ever
369
- * runs against {@link MondayCliError} instances, and it
370
- * NEVER converts a non-internal_error into internal_error,
371
- * so the re-throw path through dispatchSequential remains
372
- * the canonical schema-drift surface.
415
+ * F1 / round-3 F1, both dispatchers re-throw `internal_error`
416
+ * whole-call so schema-drift in the response surfaces as
417
+ * top-level `ok: false` rather than per-record — papering over
418
+ * `internal_error` would hide the malformed-response signal
419
+ * agents need to know about. The wrapper inherits this
420
+ * behaviour by NOT wrapping the dispatcher's re-throw —
421
+ * `foldAndRemap` only ever runs against {@link MondayCliError}
422
+ * instances, and it NEVER converts a non-internal_error into
423
+ * internal_error, so the re-throw path through the selected
424
+ * dispatcher remains the canonical schema-drift surface (axis
425
+ * 2 of the R-NEW-28 6-axis equivalence — identical between
426
+ * `dispatchSequential` and `dispatchParallel`).
373
427
  *
374
428
  * **Non-`MondayCliError` re-throw.** Programmer-bug exceptions
375
429
  * (TypeError, RangeError, etc.) raised by the executor or by
376
- * `foldAndRemap`'s refresh probe propagate through
377
- * `dispatchSequential`'s non-CliError re-throw branch unchanged,
378
- * surfacing as whole-call `internal_error` via the runner's
379
- * catch-all (mirrors M14's pattern at
380
- * `users-fan-out-mutation.ts` and the documented behaviour at
381
- * `partial-success-mutation.ts:93`).
430
+ * `foldAndRemap`'s refresh probe propagate through the selected
431
+ * dispatcher's non-CliError re-throw branch unchanged, surfacing
432
+ * as whole-call `internal_error` via the runner's catch-all
433
+ * (mirrors M14's pattern at `users-fan-out-mutation.ts` and the
434
+ * documented behaviour at `partial-success-mutation.ts`
435
+ * R-NEW-28 axis 3, also identical across both routes).
382
436
  */
383
437
  export declare const runPartialSuccessBulkUpdate: (inputs: RunPartialSuccessBulkUpdateInputs) => Promise<RunPartialSuccessBulkUpdateResult>;
384
438
  /**
385
- * Pure helper — folds a `dispatchSequential` result row + a
386
- * `ProjectedItem` side-map entry into the partial-success-bulk
387
- * per-item record shape this module emits to the action layer.
439
+ * Pure helper — folds a per-target result row produced by the
440
+ * selected dispatcher (`dispatchSequential` or
441
+ * `dispatchParallel`) + a `ProjectedItem` side-map entry into
442
+ * the partial-success-bulk per-item record shape this module
443
+ * emits to the action layer. Both dispatchers populate the row
444
+ * with the same `{item_id, ok, error?}` shape (axis 1 of the
445
+ * R-NEW-28 6-axis equivalence) so the fold is route-agnostic.
388
446
  *
389
447
  * The helper is **shipped as a real implementation** (not a
390
448
  * stub) so the pre-flight Codex review can verify the
391
449
  * projection shape against the contract pinned in cli-design
392
450
  * §6.4 inline. M25 implementation reuses the helper unchanged.
393
451
  *
394
- * `record` is the row produced by `dispatchSequential` with
452
+ * `record` is the row produced by the selected dispatcher with
395
453
  * id-field `'item_id'` — carries `{item_id, ok, error?}` per
396
454
  * the partial-success contract. `projectedItem` is the
397
455
  * `ProjectedItem` the per-item dispatch callback captured on
@@ -1 +1 @@
1
- {"version":3,"file":"partial-success-bulk.d.ts","sourceRoot":"","sources":["../../src/api/partial-success-bulk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuFG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAuB,KAAK,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAE7D;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,oCAAoC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAU/C,CAAC;AAEH,MAAM,MAAM,8BAA8B,GAAG,CAAC,CAAC,KAAK,CAClD,OAAO,oCAAoC,CAC5C,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,kCAAkC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAS7C,CAAC;AAEH,MAAM,MAAM,4BAA4B,GAAG,CAAC,CAAC,KAAK,CAChD,OAAO,kCAAkC,CAC1C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgEG;AACH,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,MAAM,EAAE,YAAY,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,QAAQ,EAAE,gBAAgB,CAAC;IACpC,QAAQ,CAAC,qBAAqB,EAAE,OAAO,GAAG,SAAS,CAAC;IACpD,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,CAAC;IAChC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;CACvD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,WAAW,iCAAiC;IAChD,QAAQ,CAAC,OAAO,EAAE,8BAA8B,EAAE,CAAC;CACpD;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,oCAAoC,EAAE,cAAuB,CAAC;AAE3E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,eAAO,MAAM,2BAA2B,GACtC,QAAQ,iCAAiC,KACxC,OAAO,CAAC,iCAAiC,CAgF3C,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,4BAA4B,GACvC,QAAQ,oBAAoB,EAC5B,eAAe,aAAa,GAAG,SAAS,KACvC,8BA4DF,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,8BAA8B,GAAI,qCAI5C;IACD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,SAAS,8BAA8B,EAAE,CAAC;CAC7D,KAAG,4BAA4B,CAAC,SAAS,CAuBzC,CAAC"}
1
+ {"version":3,"file":"partial-success-bulk.d.ts","sourceRoot":"","sources":["../../src/api/partial-success-bulk.ts"],"names":[],"mappings":"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"}
@@ -3,18 +3,20 @@
3
3
  * `item update --continue-on-error` flag (`cli-design.md` §6.4
4
4
  * "Bulk per-item partial-success" sub-section).
5
5
  *
6
- * **What this module owns.** A thin wrapper around
7
- * {@link dispatchSequential} from
8
- * `src/api/partial-success-mutation.ts` that drives the matched-
6
+ * **What this module owns.** A thin wrapper around the selected
7
+ * per-target dispatcher — {@link dispatchSequential} from
8
+ * `src/api/partial-success-mutation.ts` (default / M25 path) OR
9
+ * {@link dispatchParallel} from `src/api/parallel-dispatch.ts`
10
+ * (v0.4-M30 `--concurrency > 1` path) — that drives the matched-
9
11
  * item-ID list through one wire call per item, capturing per-
10
12
  * item failures into the result records rather than aborting
11
13
  * the loop. The wrapper sits BETWEEN the bulk command-action
12
14
  * orchestrator (`src/commands/item/update.ts:runBulk`) and the
13
- * shared `dispatchSequential` helper — the action body owns the
14
- * matched-item-walk + column-resolution pre-pass + confirmation
15
- * gate, then hands the resolved `SelectedMutation` + matched-
16
- * item IDs to this wrapper, which fans them out + projects the
17
- * partial-success envelope's `data.results[]` records.
15
+ * shared dispatcher — the action body owns the matched-item-
16
+ * walk + column-resolution pre-pass + confirmation gate, then
17
+ * hands the resolved `SelectedMutation` + matched-item IDs to
18
+ * this wrapper, which fans them out + projects the partial-
19
+ * success envelope's `data.results[]` records.
18
20
  *
19
21
  * **Why a separate module rather than folding into update.ts.**
20
22
  * Three reasons:
@@ -65,16 +67,31 @@
65
67
  * 3-consumer trigger: single-item + fail-fast bulk + M25
66
68
  * partial-success bulk).
67
69
  *
68
- * **Per-item dispatch wiring.** Runtime body loops
69
- * {@link dispatchSequential} over `matchedItemIds` with
70
- * id-field `'item_id'`. The per-item dispatch callback fires
71
- * one `executeItemMutation` call. Successes populate
72
- * `results[i].item` with the `ProjectedItem` via a side-map
73
- * fold; failures land in `results[i].error: {code, message}`
74
- * via `dispatchSequential`'s built-in error decoration.
75
- * `internal_error` codes re-throw as whole-call (M14 round-2
76
- * F1 precedentschema-drift in the response MUST NOT be
77
- * papered over as a per-item failure).
70
+ * **v0.4-M30 extension.** Adds the `concurrency` input slot +
71
+ * the routing branch to {@link dispatchParallel} (new module
72
+ * `src/api/parallel-dispatch.ts` runtime body landed at M30
73
+ * IMPL). When the caller passes `concurrency > 1`, the runtime
74
+ * fans out per-target dispatches via a bounded async-pool;
75
+ * absent or `concurrency === 1` preserves the M25 sequential
76
+ * path verbatim. The per-target dispatch closure is hoisted to
77
+ * a named local so both routes share the same
78
+ * `executeItemMutation` + `foldAndRemap` body keeps the
79
+ * R-NEW-28 6-axis behavioral-equivalence audit straightforward.
80
+ * The M30 IMPL also threads an optional `signal?: AbortSignal`
81
+ * through both dispatchers (axis-6 scheduler short-circuit).
82
+ *
83
+ * **Per-item dispatch wiring.** Runtime body routes between
84
+ * {@link dispatchSequential} (default — `concurrency` absent /
85
+ * `=== 1`) and {@link dispatchParallel} (v0.4-M30 —
86
+ * `concurrency > 1`) over `matchedItemIds` with id-field
87
+ * `'item_id'`. The per-target dispatch callback (shared between
88
+ * routes verbatim) fires one `executeItemMutation` call.
89
+ * Successes populate `results[i].item` with the `ProjectedItem`
90
+ * via a side-map fold; failures land in
91
+ * `results[i].error: {code, message}` via the dispatcher's
92
+ * built-in error decoration. `internal_error` codes re-throw
93
+ * as whole-call (M14 round-2 F1 precedent — schema-drift in
94
+ * the response MUST NOT be papered over as a per-item failure).
78
95
  *
79
96
  * **`data.summary.failed_count` invariant.** The action body
80
97
  * derives `failed_count` from the result records
@@ -90,6 +107,7 @@ import { z } from 'zod';
90
107
  import { ApiError, MondayCliError } from '../utils/errors.js';
91
108
  import { projectedItemSchema } from './item-projection.js';
92
109
  import { dispatchSequential, } from './partial-success-mutation.js';
110
+ import { dispatchParallel } from './parallel-dispatch.js';
93
111
  import { executeItemMutation } from './item-mutation-execute.js';
94
112
  import { foldAndRemap } from './resolver-error-fold.js';
95
113
  /**
@@ -102,13 +120,15 @@ import { foldAndRemap } from './resolver-error-fold.js';
102
120
  * The `item` slot on success records is the §6.2 `ProjectedItem`
103
121
  * shape (same projection single-item `item update` emits as
104
122
  * `data`). The `error` slot on failure records carries
105
- * `{code, message}` populated from
106
- * `dispatchSequential`'s per-target error decoration.
123
+ * `{code, message}` populated from the selected dispatcher's
124
+ * per-target error decoration (`dispatchSequential` or
125
+ * `dispatchParallel` — same shape per the R-NEW-28 axis-1
126
+ * equivalence).
107
127
  *
108
- * `z.discriminatedUnion` would be the natural shape but
109
- * `dispatchSequential`'s result records carry a dynamic
110
- * id-field key (`{item_id: ..., ok, error?}`) — modelling that
111
- * as a per-record union complicates the schema and downstream
128
+ * `z.discriminatedUnion` would be the natural shape but the
129
+ * dispatchers' result records carry a dynamic id-field key
130
+ * (`{item_id: ..., ok, error?}`) — modelling that as a
131
+ * per-record union complicates the schema and downstream
112
132
  * consumers' type-narrowing. The flatter shape below carries
113
133
  * `item` + `error` as optionals; the action body's projection
114
134
  * + the wrapper's per-item dispatch enforce the
@@ -160,19 +180,24 @@ export const PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE = 'live';
160
180
  /**
161
181
  * Drives the per-item dispatch loop under `--continue-on-error`.
162
182
  *
163
- * Implementation (M25 impl `78889df` refactor + this commit):
183
+ * Implementation (M25 impl `78889df` refactor + this commit;
184
+ * extended at v0.4-M30 pre-flight with the `concurrency` routing
185
+ * branch):
164
186
  *
165
- * 1. Loop {@link dispatchSequential} over `matchedItemIds`
166
- * with id-field `'item_id'`.
187
+ * 1. Loop {@link dispatchSequential} (default / M25 path) OR
188
+ * {@link dispatchParallel} (v0.4-M30 `--concurrency > 1`
189
+ * path; runtime body landed at M30 IMPL) over
190
+ * `matchedItemIds` with id-field `'item_id'`.
167
191
  * 2. Per-item dispatch callback fires
168
192
  * {@link executeItemMutation} against the resolved
169
193
  * `SelectedMutation`. On a {@link MondayCliError} catch,
170
194
  * run {@link foldAndRemap} with `resolverWarnings` +
171
195
  * `remapColumnIds` + `env` + `noCache` + `resolutionSource`
172
- * from the inputs BEFORE re-throwing into
173
- * `dispatchSequential`. This makes the per-record
174
- * `error.code` in `data.results[]` carry the SAME stable
175
- * code (`column_archived` after a stale-cache
196
+ * from the inputs BEFORE re-throwing into the selected
197
+ * dispatcher (`dispatchSequential` or `dispatchParallel`).
198
+ * This makes the per-record `error.code` in
199
+ * `data.results[]` carry the SAME stable code
200
+ * (`column_archived` after a stale-cache
176
201
  * `validation_failed` remap) that the v0.1 fail-fast
177
202
  * path would have surfaced at the top level — Codex
178
203
  * round-1 P1-1 contract requirement (cli-design §6.5
@@ -180,44 +205,57 @@ export const PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE = 'live';
180
205
  * fail-modes).
181
206
  * 3. On success, capture the `ProjectedItem` into a side
182
207
  * map keyed by `item_id`.
183
- * 4. After the loop, walk the `dispatchSequential` results
184
- * and fold the per-item `ProjectedItem` from the side
208
+ * 4. After the loop, walk the result rows (from whichever
209
+ * dispatcher fired `dispatchSequential` by default;
210
+ * {@link dispatchParallel} when `concurrency > 1`) and
211
+ * fold the per-item `ProjectedItem` from the side
185
212
  * map into each `results[i].item` slot via
186
213
  * {@link foldPartialSuccessBulkResult}. Failure records
187
214
  * already carry `error: {code, message}` (with the
188
- * foldAndRemap-applied code) via
189
- * `dispatchSequential`'s built-in error decoration.
215
+ * foldAndRemap-applied code) via the dispatcher's built-in
216
+ * error decoration (both routes share the same per-target
217
+ * error capture contract).
190
218
  * 5. Return `{results}` — the action layer folds the
191
219
  * constant `'live'` dispatch source via
192
220
  * `sourceAgg.record(PARTIAL_SUCCESS_BULK_DISPATCH_SOURCE,
193
221
  * null)` and emits the envelope.
194
222
  *
195
223
  * **`internal_error` re-throw escape hatch.** Per M14 round-2
196
- * F1 / round-3 F1, `dispatchSequential` re-throws
197
- * `internal_error` so schema-drift in the response surfaces
198
- * as whole-call (top-level `ok: false`) rather than per-record
199
- * — papering over `internal_error` would hide the malformed-
200
- * response signal agents need to know about. The M25 wrapper
201
- * inherits this behaviour by NOT wrapping the
202
- * `dispatchSequential` re-throw `foldAndRemap` only ever
203
- * runs against {@link MondayCliError} instances, and it
204
- * NEVER converts a non-internal_error into internal_error,
205
- * so the re-throw path through dispatchSequential remains
206
- * the canonical schema-drift surface.
224
+ * F1 / round-3 F1, both dispatchers re-throw `internal_error`
225
+ * whole-call so schema-drift in the response surfaces as
226
+ * top-level `ok: false` rather than per-record — papering over
227
+ * `internal_error` would hide the malformed-response signal
228
+ * agents need to know about. The wrapper inherits this
229
+ * behaviour by NOT wrapping the dispatcher's re-throw —
230
+ * `foldAndRemap` only ever runs against {@link MondayCliError}
231
+ * instances, and it NEVER converts a non-internal_error into
232
+ * internal_error, so the re-throw path through the selected
233
+ * dispatcher remains the canonical schema-drift surface (axis
234
+ * 2 of the R-NEW-28 6-axis equivalence — identical between
235
+ * `dispatchSequential` and `dispatchParallel`).
207
236
  *
208
237
  * **Non-`MondayCliError` re-throw.** Programmer-bug exceptions
209
238
  * (TypeError, RangeError, etc.) raised by the executor or by
210
- * `foldAndRemap`'s refresh probe propagate through
211
- * `dispatchSequential`'s non-CliError re-throw branch unchanged,
212
- * surfacing as whole-call `internal_error` via the runner's
213
- * catch-all (mirrors M14's pattern at
214
- * `users-fan-out-mutation.ts` and the documented behaviour at
215
- * `partial-success-mutation.ts:93`).
239
+ * `foldAndRemap`'s refresh probe propagate through the selected
240
+ * dispatcher's non-CliError re-throw branch unchanged, surfacing
241
+ * as whole-call `internal_error` via the runner's catch-all
242
+ * (mirrors M14's pattern at `users-fan-out-mutation.ts` and the
243
+ * documented behaviour at `partial-success-mutation.ts`
244
+ * R-NEW-28 axis 3, also identical across both routes).
216
245
  */
217
246
  export const runPartialSuccessBulkUpdate = async (inputs) => {
218
- const { client, boardId, matchedItemIds, mutation, createLabelsIfMissing, resolverWarnings, remapColumnIds, env, noCache, resolutionSource, } = inputs;
247
+ const { client, boardId, matchedItemIds, mutation, createLabelsIfMissing, resolverWarnings, remapColumnIds, env, noCache, resolutionSource, concurrency, signal, } = inputs;
219
248
  const projectedById = new Map();
220
- const dispatchResults = await dispatchSequential(matchedItemIds, 'item_id', async ({ targetId }) => {
249
+ // Per-target dispatch closure shared between the sequential
250
+ // (v0.3-M25 default) and parallel (v0.4-M30 `--concurrency > 1`)
251
+ // routes. Both dispatch helpers contract on the same
252
+ // {@link DispatchOneTargetInputs}-shaped callback so the closure
253
+ // body is byte-equivalent across routes — only the OUTER call
254
+ // (dispatchSequential vs dispatchParallel) changes. This keeps the
255
+ // R-NEW-28 6-axis behavioral-equivalence audit straightforward:
256
+ // every per-target outcome (success projection capture; `MondayCliError`
257
+ // foldAndRemap + re-throw; non-CliError re-throw) is shared verbatim.
258
+ const perTargetDispatch = async ({ targetId }) => {
221
259
  try {
222
260
  const result = await executeItemMutation(client, {
223
261
  mutation,
@@ -238,9 +276,9 @@ export const runPartialSuccessBulkUpdate = async (inputs) => {
238
276
  // even though the v0.1 path surfaces `column_archived`
239
277
  // for the same root cause (cli-design §6.5 stable-
240
278
  // code rule). foldAndRemap NEVER converts a non-
241
- // internal_error into internal_error, so
242
- // dispatchSequential's internal_error re-throw escape
243
- // hatch (M14 round-2 F1) stays intact.
279
+ // internal_error into internal_error, so the selected
280
+ // dispatcher's internal_error re-throw escape hatch
281
+ // (M14 round-2 F1) stays intact across both routes.
244
282
  const remapped = await foldAndRemap({
245
283
  err,
246
284
  warnings: resolverWarnings,
@@ -254,18 +292,33 @@ export const runPartialSuccessBulkUpdate = async (inputs) => {
254
292
  throw remapped;
255
293
  }
256
294
  // Non-MondayCliError — programmer bug. Re-throw through
257
- // dispatchSequential's non-CliError branch so the runner's
258
- // catch-all surfaces it as internal_error (whole-call,
259
- // not per-record). Mirrors users-fan-out-mutation.ts
260
- // and is the documented dispatchSequential contract.
295
+ // dispatchSequential / dispatchParallel's non-CliError branch
296
+ // so the runner's catch-all surfaces it as internal_error
297
+ // (whole-call, not per-record). Mirrors users-fan-out-mutation.ts
298
+ // and is the documented partial-success contract.
261
299
  throw err;
262
300
  }
263
- });
301
+ };
302
+ // v0.4-M30 routing: `--concurrency <N>` with N > 1 routes through
303
+ // {@link dispatchParallel} (bounded async-pool); absent / N === 1
304
+ // routes through the unchanged {@link dispatchSequential} path.
305
+ // Both dispatchers thread the optional `signal` so SIGINT-aware
306
+ // callers see consistent cooperative abort semantics across routes
307
+ // (R-NEW-28 axis 6).
308
+ let dispatchResults;
309
+ if (concurrency !== undefined && concurrency > 1) {
310
+ dispatchResults = await dispatchParallel(matchedItemIds, 'item_id', perTargetDispatch, concurrency, signal);
311
+ }
312
+ else {
313
+ dispatchResults = await dispatchSequential(matchedItemIds, 'item_id', perTargetDispatch, signal);
314
+ }
264
315
  const results = dispatchResults.map((row) => {
265
316
  // Side-map lookup requires the item_id string from the row;
266
317
  // foldPartialSuccessBulkResult also enforces the same
267
318
  // invariant + throws internal_error if the id-field is
268
- // missing or non-string (dispatchSequential contract).
319
+ // missing or non-string (both dispatchers populate the
320
+ // id-field slot for every result row per the partial-
321
+ // success contract).
269
322
  const itemIdSlot = row.item_id;
270
323
  const projected = typeof itemIdSlot === 'string'
271
324
  ? projectedById.get(itemIdSlot)
@@ -275,16 +328,20 @@ export const runPartialSuccessBulkUpdate = async (inputs) => {
275
328
  return { results };
276
329
  };
277
330
  /**
278
- * Pure helper — folds a `dispatchSequential` result row + a
279
- * `ProjectedItem` side-map entry into the partial-success-bulk
280
- * per-item record shape this module emits to the action layer.
331
+ * Pure helper — folds a per-target result row produced by the
332
+ * selected dispatcher (`dispatchSequential` or
333
+ * `dispatchParallel`) + a `ProjectedItem` side-map entry into
334
+ * the partial-success-bulk per-item record shape this module
335
+ * emits to the action layer. Both dispatchers populate the row
336
+ * with the same `{item_id, ok, error?}` shape (axis 1 of the
337
+ * R-NEW-28 6-axis equivalence) so the fold is route-agnostic.
281
338
  *
282
339
  * The helper is **shipped as a real implementation** (not a
283
340
  * stub) so the pre-flight Codex review can verify the
284
341
  * projection shape against the contract pinned in cli-design
285
342
  * §6.4 inline. M25 implementation reuses the helper unchanged.
286
343
  *
287
- * `record` is the row produced by `dispatchSequential` with
344
+ * `record` is the row produced by the selected dispatcher with
288
345
  * id-field `'item_id'` — carries `{item_id, ok, error?}` per
289
346
  * the partial-success contract. `projectedItem` is the
290
347
  * `ProjectedItem` the per-item dispatch callback captured on
@@ -297,16 +354,17 @@ export const runPartialSuccessBulkUpdate = async (inputs) => {
297
354
  * records never carry `item`.
298
355
  */
299
356
  export const foldPartialSuccessBulkResult = (record, projectedItem) => {
300
- // Dot-access: `dispatchSequential` builds the record with
301
- // the dynamic id-field key (`'item_id'`) carrying the target
302
- // ID. The dot-access narrows the unknown index-signature
303
- // value to a string via the runtime guard below; the helper
304
- // throws `internal_error` if the shape doesn't match (which
305
- // would be a programmer bug `dispatchSequential`'s contract
306
- // is to populate the id-field slot for every result row).
357
+ // Dot-access: the selected dispatcher (`dispatchSequential` or
358
+ // `dispatchParallel`) builds the record with the dynamic
359
+ // id-field key (`'item_id'`) carrying the target ID. The
360
+ // dot-access narrows the unknown index-signature value to a
361
+ // string via the runtime guard below; the helper throws
362
+ // `internal_error` if the shape doesn't match (which would be
363
+ // a programmer bug both dispatchers contract on populating
364
+ // the id-field slot for every result row).
307
365
  const itemIdSlot = record.item_id;
308
366
  if (typeof itemIdSlot !== 'string' || itemIdSlot.length === 0) {
309
- throw new ApiError('internal_error', 'partial-success bulk result row is missing the `item_id` field — dispatchSequential contract violation.', {
367
+ throw new ApiError('internal_error', 'partial-success bulk result row is missing the `item_id` field — dispatcher contract violation.', {
310
368
  details: {
311
369
  record_keys: Object.keys(record),
312
370
  },
@@ -326,11 +384,11 @@ export const foldPartialSuccessBulkResult = (record, projectedItem) => {
326
384
  item: projectedItem,
327
385
  };
328
386
  }
329
- // Failure path — `dispatchSequential` populates `error` on
330
- // every non-`ok` row; the schema's `.optional()` declarations
331
- // narrow defensively here.
387
+ // Failure path — both dispatchers populate `error` on every
388
+ // non-`ok` row (R-NEW-28 axis 1); the schema's `.optional()`
389
+ // declarations narrow defensively here.
332
390
  if (record.error === undefined) {
333
- throw new ApiError('internal_error', `partial-success bulk result row for item_id ${itemIdSlot} reported ok: false but no error payload was captured — dispatchSequential contract violation.`, {
391
+ throw new ApiError('internal_error', `partial-success bulk result row for item_id ${itemIdSlot} reported ok: false but no error payload was captured — dispatcher contract violation.`, {
334
392
  details: {
335
393
  item_id: itemIdSlot,
336
394
  },