@cleocode/contracts 2026.5.122 → 2026.5.123

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 (108) hide show
  1. package/dist/__tests__/completion-operation-contracts.test.d.ts +8 -0
  2. package/dist/__tests__/completion-operation-contracts.test.d.ts.map +1 -0
  3. package/dist/__tests__/completion-operation-contracts.test.js +114 -0
  4. package/dist/__tests__/completion-operation-contracts.test.js.map +1 -0
  5. package/dist/__tests__/operation-envelope-validation.test.d.ts +8 -0
  6. package/dist/__tests__/operation-envelope-validation.test.d.ts.map +1 -0
  7. package/dist/__tests__/operation-envelope-validation.test.js +105 -0
  8. package/dist/__tests__/operation-envelope-validation.test.js.map +1 -0
  9. package/dist/__tests__/satisfies-atom.test.js +21 -3
  10. package/dist/__tests__/satisfies-atom.test.js.map +1 -1
  11. package/dist/__tests__/workgraph-context-scaffold-contracts.test.d.ts +8 -0
  12. package/dist/__tests__/workgraph-context-scaffold-contracts.test.d.ts.map +1 -0
  13. package/dist/__tests__/workgraph-context-scaffold-contracts.test.js +188 -0
  14. package/dist/__tests__/workgraph-context-scaffold-contracts.test.js.map +1 -0
  15. package/dist/__tests__/workgraph-operation-contracts.test.d.ts +8 -0
  16. package/dist/__tests__/workgraph-operation-contracts.test.d.ts.map +1 -0
  17. package/dist/__tests__/workgraph-operation-contracts.test.js +115 -0
  18. package/dist/__tests__/workgraph-operation-contracts.test.js.map +1 -0
  19. package/dist/data-accessor.d.ts +77 -0
  20. package/dist/data-accessor.d.ts.map +1 -1
  21. package/dist/data-accessor.js.map +1 -1
  22. package/dist/dispatch/__tests__/docs-update-registry.test.d.ts +2 -0
  23. package/dist/dispatch/__tests__/docs-update-registry.test.d.ts.map +1 -0
  24. package/dist/dispatch/__tests__/docs-update-registry.test.js +27 -0
  25. package/dist/dispatch/__tests__/docs-update-registry.test.js.map +1 -0
  26. package/dist/dispatch/__tests__/operation-envelope-snapshots.test.d.ts +2 -0
  27. package/dist/dispatch/__tests__/operation-envelope-snapshots.test.d.ts.map +1 -0
  28. package/dist/dispatch/__tests__/operation-envelope-snapshots.test.js +265 -0
  29. package/dist/dispatch/__tests__/operation-envelope-snapshots.test.js.map +1 -0
  30. package/dist/dispatch/operations-registry.d.ts.map +1 -1
  31. package/dist/dispatch/operations-registry.js +487 -7
  32. package/dist/dispatch/operations-registry.js.map +1 -1
  33. package/dist/evidence-atom-schema.d.ts +4 -4
  34. package/dist/evidence-atom-schema.d.ts.map +1 -1
  35. package/dist/evidence-atom-schema.js +9 -9
  36. package/dist/evidence-atom-schema.js.map +1 -1
  37. package/dist/index.d.ts +12 -6
  38. package/dist/index.d.ts.map +1 -1
  39. package/dist/index.js +8 -0
  40. package/dist/index.js.map +1 -1
  41. package/dist/operation-envelope-validation.d.ts +79 -0
  42. package/dist/operation-envelope-validation.d.ts.map +1 -0
  43. package/dist/operation-envelope-validation.js +219 -0
  44. package/dist/operation-envelope-validation.js.map +1 -0
  45. package/dist/operations/__tests__/agent-operation-contract.test.d.ts +2 -0
  46. package/dist/operations/__tests__/agent-operation-contract.test.d.ts.map +1 -0
  47. package/dist/operations/__tests__/agent-operation-contract.test.js +128 -0
  48. package/dist/operations/__tests__/agent-operation-contract.test.js.map +1 -0
  49. package/dist/operations/__tests__/tasks-input-contracts.test.js +15 -0
  50. package/dist/operations/__tests__/tasks-input-contracts.test.js.map +1 -1
  51. package/dist/operations/agent-operation-contract.d.ts +227 -0
  52. package/dist/operations/agent-operation-contract.d.ts.map +1 -0
  53. package/dist/operations/agent-operation-contract.js +38 -0
  54. package/dist/operations/agent-operation-contract.js.map +1 -0
  55. package/dist/operations/docs.d.ts +19 -1
  56. package/dist/operations/docs.d.ts.map +1 -1
  57. package/dist/operations/docs.js +20 -0
  58. package/dist/operations/docs.js.map +1 -1
  59. package/dist/operations/focus.d.ts +1 -1
  60. package/dist/operations/index.d.ts +1 -0
  61. package/dist/operations/index.d.ts.map +1 -1
  62. package/dist/operations/index.js +1 -0
  63. package/dist/operations/index.js.map +1 -1
  64. package/dist/operations/orchestrate.d.ts +66 -0
  65. package/dist/operations/orchestrate.d.ts.map +1 -1
  66. package/dist/operations/tasks.d.ts +568 -11
  67. package/dist/operations/tasks.d.ts.map +1 -1
  68. package/dist/operations/tasks.js +22 -3
  69. package/dist/operations/tasks.js.map +1 -1
  70. package/dist/task-record.d.ts +15 -0
  71. package/dist/task-record.d.ts.map +1 -1
  72. package/dist/task.d.ts +15 -6
  73. package/dist/task.d.ts.map +1 -1
  74. package/dist/task.js.map +1 -1
  75. package/dist/tasks.d.ts +944 -0
  76. package/dist/tasks.d.ts.map +1 -1
  77. package/dist/tasks.js +198 -1
  78. package/dist/tasks.js.map +1 -1
  79. package/dist/workgraph.d.ts +1950 -0
  80. package/dist/workgraph.d.ts.map +1 -0
  81. package/dist/workgraph.js +449 -0
  82. package/dist/workgraph.js.map +1 -0
  83. package/package.json +10 -2
  84. package/src/__tests__/__snapshots__/operations-registry.test.ts.snap +1 -1
  85. package/src/__tests__/completion-operation-contracts.test.ts +154 -0
  86. package/src/__tests__/operation-envelope-validation.test.ts +140 -0
  87. package/src/__tests__/satisfies-atom.test.ts +23 -3
  88. package/src/__tests__/workgraph-context-scaffold-contracts.test.ts +232 -0
  89. package/src/__tests__/workgraph-operation-contracts.test.ts +151 -0
  90. package/src/data-accessor.ts +94 -1
  91. package/src/dispatch/__tests__/docs-update-registry.test.ts +35 -0
  92. package/src/dispatch/__tests__/operation-envelope-snapshots.test.ts +283 -0
  93. package/src/dispatch/operations-registry.ts +502 -7
  94. package/src/evidence-atom-schema.ts +10 -10
  95. package/src/index.ts +193 -2
  96. package/src/operation-envelope-validation.ts +319 -0
  97. package/src/operations/__tests__/agent-operation-contract.test.ts +161 -0
  98. package/src/operations/__tests__/tasks-input-contracts.test.ts +30 -0
  99. package/src/operations/agent-operation-contract.ts +253 -0
  100. package/src/operations/docs.ts +27 -7
  101. package/src/operations/focus.ts +1 -1
  102. package/src/operations/index.ts +1 -0
  103. package/src/operations/orchestrate.ts +71 -0
  104. package/src/operations/tasks.ts +612 -15
  105. package/src/task-record.ts +16 -0
  106. package/src/task.ts +16 -6
  107. package/src/tasks.ts +558 -0
  108. package/src/workgraph.ts +1153 -0
@@ -26,7 +26,7 @@ import type { TaskStatus } from '../status-registry.js';
26
26
  import type { TaskPriority, TaskType } from '../task.js';
27
27
  import type { TaskRecord } from '../task-record.js';
28
28
  import type { ExternalTask, ExternalTaskLink, ReconcileResult } from '../task-sync.js';
29
- import type { TaskComplexityFactor, TaskDependsResult, TaskLabelInfo, TaskPlanResult, TaskTreeNode, TaskView } from '../tasks.js';
29
+ import type { CompletionEvaluateParams, CompletionEvaluateResult, CompletionExplainParams, CompletionExplainResult, CompletionListParams, CompletionListResult, CompletionProjectionRepairParams, CompletionProjectionRepairResult, TaskComplexityFactor, TaskDependsResult, TaskLabelInfo, TaskMutationDryRunSummary, TaskMutationEnvelope, TaskMutationWarning, TaskPlanResult, TaskTreeNode, TaskView } from '../tasks.js';
30
30
  import type { DocsType } from './docs.js';
31
31
  import type { JsonSchema, OperationInputContract } from './input-contract.js';
32
32
  export type { TaskPriority, TaskStatus };
@@ -165,6 +165,8 @@ export interface TasksShowParams {
165
165
  history?: boolean;
166
166
  /** When true, include IVTR phase history. */
167
167
  ivtrHistory?: boolean;
168
+ /** When true, include expanded relation/doc ID lists alongside compact counts. */
169
+ relations?: boolean;
168
170
  }
169
171
  /**
170
172
  * Minimal attachment entry surfaced in the `tasks.show` envelope.
@@ -192,6 +194,27 @@ export interface TaskShowAttachmentEntry {
192
194
  /** Storage kind — discriminant for the full attachment variant. */
193
195
  kind: string;
194
196
  }
197
+ export interface TaskShowRelationsEntry {
198
+ /** Direct dependency IDs. */
199
+ depends: string[];
200
+ /** Explicit blockedBy entries from the task record. */
201
+ blockedBy: string[];
202
+ /** Non-dependency task relation links. */
203
+ relates: Array<{
204
+ taskId: string;
205
+ type: string;
206
+ reason?: string;
207
+ }>;
208
+ /** Direct child task IDs. */
209
+ children: string[];
210
+ /** Linked docs attachment IDs/slugs. */
211
+ docs: Array<{
212
+ attachmentId: string;
213
+ slug?: string;
214
+ type?: DocsType;
215
+ kind: string;
216
+ }>;
217
+ }
195
218
  /**
196
219
  * Result of `tasks.show` — the full task record plus its canonical view
197
220
  * projection. `view` is null when the task has no lifecycle pipeline.
@@ -227,6 +250,8 @@ export interface TasksShowResult {
227
250
  * @epic T10381
228
251
  */
229
252
  acRows?: TaskShowAcRowEntry[];
253
+ /** Expanded relation/doc lists returned only when `cleo show --relations` is requested. */
254
+ relations?: TaskShowRelationsEntry;
230
255
  }
231
256
  /**
232
257
  * One acceptance-criterion entry in {@link TasksShowResult.acRows}.
@@ -308,6 +333,48 @@ export interface TasksDependsParams {
308
333
  * @task T1703
309
334
  */
310
335
  export type TasksDependsResult = TaskDependsResult;
336
+ /** Localized task/workgraph node returned by `tasks.slice`. */
337
+ export interface TasksSliceNode {
338
+ id: string;
339
+ title: string;
340
+ status: TaskStatus;
341
+ type?: TaskType;
342
+ priority?: TaskPriority;
343
+ /** Canonical wire field for parent task ID (ADR-057 D2). */
344
+ parent?: string;
345
+ children: string[];
346
+ depends: string[];
347
+ dependents: string[];
348
+ depth: number;
349
+ }
350
+ /** Params for `tasks.slice` — fixed-radius local WorkGraph context around a task. */
351
+ export interface TasksSliceParams {
352
+ taskId: string;
353
+ /** Slice direction. `around` returns upstream, downstream, and siblings. Defaults to `around`. */
354
+ direction?: 'upstream' | 'downstream' | 'around';
355
+ /** Back-compat alias for dependency traversal depth. */
356
+ radius?: number;
357
+ /** Dependency traversal depth for upstream/downstream. Defaults to 1. */
358
+ depth?: number;
359
+ /** Maximum nodes per returned section. Defaults to unbounded. */
360
+ budget?: number;
361
+ /** Include direct non-dependency `relates` neighbors in a `related` bucket. */
362
+ includeRelates?: boolean;
363
+ }
364
+ /** Result of `tasks.slice` — center task, deps, dependents, siblings, and optional relations. */
365
+ export interface TasksSliceResult {
366
+ taskId: string;
367
+ direction: 'upstream' | 'downstream' | 'around';
368
+ depth: number;
369
+ radius: number;
370
+ budget?: number;
371
+ includeRelates: boolean;
372
+ center: TasksSliceNode;
373
+ upstream: TasksSliceNode[];
374
+ downstream: TasksSliceNode[];
375
+ siblings: TasksSliceNode[];
376
+ related?: TasksSliceNode[];
377
+ }
311
378
  export interface TasksAnalyzeQueryParams {
312
379
  taskId?: string;
313
380
  tierLimit?: number;
@@ -323,6 +390,196 @@ export interface TasksAnalyzeQueryParams {
323
390
  export type TasksAnalyzeQueryResult = TaskAnalysisResult & {
324
391
  tierLimit: number;
325
392
  };
393
+ /** Params for `tasks.context` — bounded task context pack. */
394
+ export interface TasksContextParams {
395
+ /** Task ID to build context for. */
396
+ taskId: string;
397
+ /**
398
+ * Scope mode: `saga` resolves member-epic rollup + ready frontier across
399
+ * all members; `epic` resolves child-task rollup + ready frontier for the
400
+ * epic. When omitted or `undefined`, behaves as a single-task context pack
401
+ * (T10629 baseline). @defaultValue undefined (task-only)
402
+ */
403
+ scope?: 'saga' | 'epic';
404
+ /** Maximum token budget for the returned pack. @defaultValue 1500 */
405
+ budgetTokens?: number;
406
+ /** Include acceptance criteria in the pack. @defaultValue true */
407
+ includeAcceptance?: boolean;
408
+ /** Include blocker summary in the pack. @defaultValue true */
409
+ includeBlockers?: boolean;
410
+ /** Include attached docs in the pack. @defaultValue true */
411
+ includeDocs?: boolean;
412
+ /** Include graph edges (upstream/downstream/siblings/related) in the pack. @defaultValue true */
413
+ includeEdges?: boolean;
414
+ /** Include recent activity (audit log) in the pack. @defaultValue true */
415
+ includeActivity?: boolean;
416
+ /** Maximum number of recent activity events. @defaultValue 10 */
417
+ activityLimit?: number;
418
+ /** Maximum depth for graph edges when includeEdges is true. @defaultValue 1 */
419
+ edgeDepth?: number;
420
+ }
421
+ /** A single omitted section with reason and count. */
422
+ export interface TasksContextOmission {
423
+ /** Section path that was omitted (e.g. "acceptance", "blockers", "docs", "edges.upstream", "activity"). */
424
+ path: string;
425
+ /** Reason for omission. */
426
+ reason: 'budget_exceeded' | 'not_requested' | 'not_available';
427
+ /** Human-readable explanation. */
428
+ message: string;
429
+ /** Number of items omitted, when countable. */
430
+ count?: number;
431
+ /**
432
+ * CLI command to expand this section, when an expansion path exists
433
+ * (e.g. `"cleo orchestrate ready T10547"`, `"cleo saga rollup T10538"`).
434
+ * @task T10630
435
+ */
436
+ expansionCommand?: string;
437
+ }
438
+ /** Budget accounting for a task context pack. */
439
+ export interface TasksContextBudget {
440
+ /** Caller-provided token budget. */
441
+ tokenBudget: number;
442
+ /** Estimated tokens consumed by the returned payload. */
443
+ estimatedTokens: number;
444
+ /** Remaining tokens after payload selection. */
445
+ remainingTokens: number;
446
+ /** True when one or more sections were truncated or omitted. */
447
+ truncated: boolean;
448
+ }
449
+ /** Single AC entry in the context pack. */
450
+ export interface TasksContextAcceptanceEntry {
451
+ /** AC alias (e.g. "AC1") or UUID. */
452
+ alias: string;
453
+ /** Full acceptance criterion text. */
454
+ text: string;
455
+ /** Whether this AC has evidence bindings. */
456
+ hasEvidence?: boolean;
457
+ }
458
+ /** Single blocker entry in the context pack. */
459
+ export interface TasksContextBlockerEntry {
460
+ /** Blocking task ID. */
461
+ taskId: string;
462
+ /** Title of the blocking task. */
463
+ title: string;
464
+ /** Status of the blocking task. */
465
+ status: string;
466
+ /** Blocker kind: dependency or gate. */
467
+ kind: 'dependency' | 'gate';
468
+ }
469
+ /** Single doc entry in the context pack. */
470
+ export interface TasksContextDocEntry {
471
+ /** Doc slug or attachment identifier. */
472
+ slug: string;
473
+ /** Doc type. */
474
+ type: string;
475
+ /** Human-readable title or description. */
476
+ title: string;
477
+ }
478
+ /** Single activity event in the context pack. */
479
+ export interface TasksContextActivityEvent {
480
+ /** ISO timestamp. */
481
+ timestamp: string;
482
+ /** Action type. */
483
+ action: string;
484
+ /** Actor who performed the action. */
485
+ actor?: string;
486
+ /** Free-form details. */
487
+ details?: string;
488
+ }
489
+ /**
490
+ * Rollup summary for a saga or epic scope.
491
+ * @task T10630
492
+ */
493
+ export interface TasksScopeRollup {
494
+ /** Total number of member epics (saga) or child tasks (epic). */
495
+ total: number;
496
+ done: number;
497
+ active: number;
498
+ blocked: number;
499
+ pending: number;
500
+ /** Completion percentage (0–100). */
501
+ completionPct: number;
502
+ }
503
+ /**
504
+ * A single member epic entry in a saga context pack.
505
+ * @task T10630
506
+ */
507
+ export interface TasksScopeMember {
508
+ /** Epic task ID. */
509
+ epicId: string;
510
+ /** Epic title. */
511
+ title: string;
512
+ /** Current status. */
513
+ status: string;
514
+ }
515
+ /**
516
+ * A single ready-frontier entry in a saga/epic context pack.
517
+ * @task T10630
518
+ */
519
+ export interface TasksScopeReadyEntry {
520
+ /** Task ID that is ready to execute. */
521
+ id: string;
522
+ /** Task title. */
523
+ title: string;
524
+ /** Priority level. */
525
+ priority: string;
526
+ /** Declared dependency IDs. */
527
+ depends: string[];
528
+ }
529
+ /** Result of `tasks.context` — bounded task context pack with omission tracking. */
530
+ export interface TasksContextResult {
531
+ /** Task ID this pack describes. */
532
+ taskId: string;
533
+ /** ISO timestamp when the pack was generated. */
534
+ generatedAt: string;
535
+ /** Budget accounting. */
536
+ budget: TasksContextBudget;
537
+ /** Task identity (title, status, type, priority, description). */
538
+ identity: {
539
+ id: string;
540
+ title: string;
541
+ status: string;
542
+ type?: string;
543
+ priority?: string;
544
+ description?: string;
545
+ parentId?: string | null;
546
+ };
547
+ /** Acceptance criteria, when requested and within budget. */
548
+ acceptance?: TasksContextAcceptanceEntry[];
549
+ /** Blockers, when requested and within budget. */
550
+ blockers?: TasksContextBlockerEntry[];
551
+ /** Attached docs, when requested and within budget. */
552
+ docs?: TasksContextDocEntry[];
553
+ /** Graph edges, when requested and within budget. */
554
+ edges?: {
555
+ upstream: TasksSliceNode[];
556
+ downstream: TasksSliceNode[];
557
+ siblings: TasksSliceNode[];
558
+ related?: TasksSliceNode[];
559
+ };
560
+ /** Recent activity events, when requested and within budget. */
561
+ activity?: TasksContextActivityEvent[];
562
+ /**
563
+ * Saga/epic rollup summary — present when `scope` is `'saga'` or
564
+ * `'epic'` and rollup data is available. @task T10630
565
+ */
566
+ rollup?: TasksScopeRollup;
567
+ /**
568
+ * Saga member epics — present when `scope` is `'saga'` and member data
569
+ * is available. @task T10630
570
+ */
571
+ members?: TasksScopeMember[];
572
+ /**
573
+ * Ready frontier — parallel-safe tasks that can be dispatched now.
574
+ * Present when `scope` is `'saga'` or `'epic'` and ready data is
575
+ * available. @task T10630
576
+ */
577
+ readyFrontier?: TasksScopeReadyEntry[];
578
+ /** Omitted/truncated sections with reasons and counts. */
579
+ omissions: TasksContextOmission[];
580
+ /** Expansion hints for omitted sections. */
581
+ expansionHints: Record<string, string>;
582
+ }
326
583
  /**
327
584
  * Parameters for `tasks.deps.validate`.
328
585
  *
@@ -466,6 +723,12 @@ export interface TasksRelatesParams {
466
723
  taskId: string;
467
724
  mode?: 'suggest' | 'discover';
468
725
  threshold?: number;
726
+ /** List edges where taskId is the source, target, or either side. Defaults to both. */
727
+ direction?: 'out' | 'in' | 'both';
728
+ /** Filter by relation type, or `depends`/`depends_on` for dependency edges. */
729
+ type?: string;
730
+ /** Include scheduler dependency edges in list output. Defaults to true. */
731
+ includeDependencies?: boolean;
469
732
  }
470
733
  /**
471
734
  * Result of `tasks.relates` — task relations list.
@@ -480,10 +743,52 @@ export interface TasksRelatesResult {
480
743
  taskId: string;
481
744
  type: string;
482
745
  reason?: string;
746
+ direction?: 'out' | 'in';
747
+ source?: 'relation' | 'dependency';
748
+ ready?: boolean;
749
+ status?: string;
483
750
  }>;
751
+ /** Direction filter applied by list output. */
752
+ direction?: 'out' | 'in' | 'both';
484
753
  /** Total number of relations. */
485
754
  count: number;
486
755
  }
756
+ export interface TasksRelatesAddBatchEntry {
757
+ taskId?: string;
758
+ from?: string;
759
+ relatedId?: string;
760
+ to?: string;
761
+ type: string;
762
+ reason?: string;
763
+ }
764
+ export interface TasksRelatesAddBatchParams {
765
+ relations?: TasksRelatesAddBatchEntry[];
766
+ edges?: TasksRelatesAddBatchEntry[];
767
+ dryRun?: boolean;
768
+ reasonWaiver?: string;
769
+ }
770
+ export interface TasksRelatesAddBatchResult {
771
+ dryRun: boolean;
772
+ validatedCount: number;
773
+ created: number;
774
+ wouldCreate: number;
775
+ relations: Array<{
776
+ from: string;
777
+ to: string;
778
+ type: string;
779
+ reason?: string;
780
+ waivedReason?: boolean;
781
+ }>;
782
+ warnings: Array<{
783
+ code: string;
784
+ message: string;
785
+ edge?: {
786
+ from: string;
787
+ to: string;
788
+ type: string;
789
+ };
790
+ }>;
791
+ }
487
792
  export interface TasksComplexityEstimateParams {
488
793
  taskId: string;
489
794
  }
@@ -578,6 +883,14 @@ export interface TasksSyncLinksRemoveResult {
578
883
  export interface TasksCancelParams {
579
884
  taskId: string;
580
885
  reason?: string;
886
+ /** Explicit child handling mode. Defaults to 'block' so propagation is never implicit. */
887
+ children?: 'block' | 'cascade' | 'orphan';
888
+ /** Operator waiver for large cascade cancellation. */
889
+ force?: boolean;
890
+ /** Large-subtree cascade guard threshold. Defaults to 10 descendants. */
891
+ cascadeThreshold?: number;
892
+ /** Config-level cascade permission. Defaults to true. */
893
+ allowCascade?: boolean;
581
894
  }
582
895
  /**
583
896
  * Result of `tasks.cancel` — cancellation confirmation.
@@ -602,6 +915,12 @@ export interface TasksCancelResult {
602
915
  * @defaultValue undefined
603
916
  */
604
917
  alreadyCancelled?: boolean;
918
+ /** Explicit child handling mode applied by the operation. */
919
+ childStrategy?: 'block' | 'cascade' | 'orphan';
920
+ /** Child or descendant tasks affected by cascade/orphan handling. */
921
+ affectedTasks?: string[];
922
+ /** Count of affected child/descendant tasks. */
923
+ affectedCount?: number;
605
924
  }
606
925
  export interface TasksRestoreParams {
607
926
  taskId: string;
@@ -688,6 +1007,58 @@ export interface TasksRelatesAddResult {
688
1007
  /** Whether the relation was newly created (false if it already existed). */
689
1008
  added: boolean;
690
1009
  }
1010
+ export interface TasksRelatesAddBatchEntry {
1011
+ /** Source task ID. */
1012
+ taskId?: string;
1013
+ /** Source task ID alias accepted by file payloads. */
1014
+ from?: string;
1015
+ /** Target task ID. */
1016
+ relatedId?: string;
1017
+ /** Target task ID alias accepted by file payloads. */
1018
+ to?: string;
1019
+ /** Relation type: related|blocks|duplicates|absorbs|fixes|extends|supersedes|groups. */
1020
+ type: string;
1021
+ /** Audit reason for creating this advisory relation. Required unless reasonWaiver is set. */
1022
+ reason?: string;
1023
+ }
1024
+ export interface TasksRelatesAddBatchParams {
1025
+ /** Relation edges to add atomically. */
1026
+ relations?: TasksRelatesAddBatchEntry[];
1027
+ /** Relation edges alias for WorkGraph-flavored callers. */
1028
+ edges?: TasksRelatesAddBatchEntry[];
1029
+ /** Validate and report without writing. */
1030
+ dryRun?: boolean;
1031
+ /** Explicit reason-waiver text applied to any edge missing an edge-level reason. */
1032
+ reasonWaiver?: string;
1033
+ }
1034
+ export interface TasksRelatesAddBatchResult {
1035
+ /** Whether this dispatch only previewed writes. */
1036
+ dryRun: boolean;
1037
+ /** Validated relation count. */
1038
+ validatedCount: number;
1039
+ /** Number of relation rows inserted or previewed. */
1040
+ created: number;
1041
+ /** Dry-run prediction of rows that would be inserted. */
1042
+ wouldCreate: number;
1043
+ /** Accepted normalized relation edges. */
1044
+ relations: Array<{
1045
+ from: string;
1046
+ to: string;
1047
+ type: string;
1048
+ reason?: string;
1049
+ waivedReason?: boolean;
1050
+ }>;
1051
+ /** Non-fatal audit notes, including explicit missing-reason waivers. */
1052
+ warnings: Array<{
1053
+ code: string;
1054
+ message: string;
1055
+ edge?: {
1056
+ from: string;
1057
+ to: string;
1058
+ type: string;
1059
+ };
1060
+ }>;
1061
+ }
691
1062
  export interface TasksRelatesRemoveParams {
692
1063
  /** Source task ID. */
693
1064
  taskId: string;
@@ -754,14 +1125,71 @@ export interface TasksAddBatchParams {
754
1125
  * Result of `tasks.add-batch`.
755
1126
  *
756
1127
  * @task T9814
1128
+ * @task T10599 (dry-run semantics: wouldCreate, wouldAffect, validatedCount, insertedCount, validationFindings)
757
1129
  */
758
- export interface TasksAddBatchResult {
1130
+ export interface TasksAddBatchResult extends TaskMutationEnvelope<number, [], []> {
759
1131
  /** Number of tasks actually created (0 on rollback or dry-run). */
760
1132
  created: number;
761
1133
  /** Per-task results in input order. */
762
1134
  tasks: TasksAddResult[];
763
1135
  /** Whether this was a dry run. */
764
1136
  dryRun?: boolean;
1137
+ /**
1138
+ * Number of tasks that would be created if the dry run were executed for real.
1139
+ * Only present when `dryRun` is `true`. Use this for `--output count` in
1140
+ * dry-run mode — `created` is always 0 in a dry run.
1141
+ *
1142
+ * @task T10599
1143
+ */
1144
+ wouldCreate?: number;
1145
+ /**
1146
+ * Generic number of rows/entities that would be affected by the dry-run operation.
1147
+ * For `tasks.add-batch`, this equals `wouldCreate`.
1148
+ *
1149
+ * @task T10599
1150
+ */
1151
+ wouldAffect?: number;
1152
+ /**
1153
+ * Number of task specs that successfully passed validation during a dry run.
1154
+ * Always equals `wouldCreate` when no validation errors occurred; may be less
1155
+ * when partial validation failures are tolerated.
1156
+ *
1157
+ * @task T10599
1158
+ */
1159
+ validatedCount?: number;
1160
+ /**
1161
+ * Number of tasks durably written to the database.
1162
+ * - Live run: equals `created`.
1163
+ * - Dry run: always `0` (no writes performed).
1164
+ *
1165
+ * Kept separate from `created` so callers can distinguish "batch was a
1166
+ * dry run with 0 writes" from "batch was live but created nothing due to
1167
+ * rollback/validation failure".
1168
+ *
1169
+ * @task T10599
1170
+ */
1171
+ insertedCount?: number;
1172
+ /**
1173
+ * Per-task non-blocking validation warnings emitted during a dry run.
1174
+ * Only present when at least one task spec produced a warning.
1175
+ * Index matches the position of the spec in the `tasks` input array.
1176
+ *
1177
+ * @task T10599
1178
+ */
1179
+ validationFindings?: Array<{
1180
+ index: number;
1181
+ warnings: string[];
1182
+ }>;
1183
+ /** Standard dry-run/preflight projection shared by task mutations. @task T10608 */
1184
+ dryRunSummary?: TaskMutationDryRunSummary;
1185
+ /** Structured partial-success warnings, flattened across batch entries. @task T10608 */
1186
+ mutationWarnings: TaskMutationWarning[];
1187
+ /** Updated task records; empty for add-batch. @task T10608 */
1188
+ updated: [];
1189
+ /** Deleted task records; empty for add-batch. @task T10608 */
1190
+ deleted: [];
1191
+ /** Total number of live rows/entities affected. @task T10608 */
1192
+ affectedCount: number;
765
1193
  }
766
1194
  export interface TasksAddParams {
767
1195
  title: string;
@@ -799,7 +1227,7 @@ export interface TasksAddParams {
799
1227
  *
800
1228
  * @task T1703
801
1229
  */
802
- export interface TasksAddResult {
1230
+ export interface TasksAddResult extends TaskMutationEnvelope<TaskRecord[], [], []> {
803
1231
  /** The created task record. */
804
1232
  task: TaskRecord;
805
1233
  /** Whether a duplicate was detected (but bypassed via forceDuplicate). */
@@ -808,6 +1236,18 @@ export interface TasksAddResult {
808
1236
  dryRun?: boolean;
809
1237
  /** Non-blocking validation warnings. @defaultValue undefined */
810
1238
  warnings?: string[];
1239
+ /** Standardized created bucket; contains `task` on live create, empty on dry-run. @task T10608 */
1240
+ created: TaskRecord[];
1241
+ /** Standardized updated bucket; empty for create. @task T10608 */
1242
+ updated: [];
1243
+ /** Standardized deleted bucket; empty for create. @task T10608 */
1244
+ deleted: [];
1245
+ /** Total number of live rows/entities affected. @task T10608 */
1246
+ affectedCount: number;
1247
+ /** Structured partial-success/preflight warnings. @task T10608 */
1248
+ mutationWarnings: TaskMutationWarning[];
1249
+ /** Standard dry-run/preflight projection. @task T10608 */
1250
+ dryRunSummary?: TaskMutationDryRunSummary;
811
1251
  }
812
1252
  export interface TasksUpdateQueryParams {
813
1253
  taskId: string;
@@ -871,11 +1311,25 @@ export interface TasksUpdateQueryParams {
871
1311
  *
872
1312
  * @task T1703
873
1313
  */
874
- export interface TasksUpdateQueryResult {
1314
+ export interface TasksUpdateQueryResult extends TaskMutationEnvelope<[], TaskRecord[], []> {
875
1315
  /** Updated task record. */
876
1316
  task: TaskRecord;
877
1317
  /** Human-readable list of fields that were changed. @defaultValue undefined */
878
1318
  changes?: string[];
1319
+ /** Whether this was a dry run (no mutation persisted). @defaultValue undefined */
1320
+ dryRun?: boolean;
1321
+ /** Standardized created bucket; empty for update. @task T10608 */
1322
+ created: [];
1323
+ /** Standardized updated bucket; contains the updated task on live update, empty on dry-run. @task T10608 */
1324
+ updated: TaskRecord[];
1325
+ /** Standardized deleted bucket; empty for update. @task T10608 */
1326
+ deleted: [];
1327
+ /** Total number of live rows/entities affected. @task T10608 */
1328
+ affectedCount: number;
1329
+ /** Structured partial-success/preflight warnings. @task T10608 */
1330
+ mutationWarnings: TaskMutationWarning[];
1331
+ /** Standard dry-run/preflight projection. @task T10608 */
1332
+ dryRunSummary?: TaskMutationDryRunSummary;
879
1333
  }
880
1334
  export interface TasksCompleteQueryParams {
881
1335
  taskId: string;
@@ -934,13 +1388,25 @@ export interface TasksDeleteQueryParams {
934
1388
  *
935
1389
  * @task T1703
936
1390
  */
937
- export interface TasksDeleteQueryResult {
1391
+ export interface TasksDeleteQueryResult extends TaskMutationEnvelope<[], [], boolean> {
938
1392
  /** The deleted task record. */
939
1393
  deletedTask: TaskRecord;
940
1394
  /** Whether the deletion was applied (always true on success). */
941
1395
  deleted: boolean;
942
1396
  /** IDs of child tasks cascade-deleted along with the parent. @defaultValue undefined */
943
1397
  cascadeDeleted?: string[];
1398
+ /** Whether this was a dry run (no mutation persisted). @defaultValue undefined */
1399
+ dryRun?: boolean;
1400
+ /** Standardized created bucket; empty for delete. @task T10608 */
1401
+ created: [];
1402
+ /** Standardized updated bucket; empty for delete. @task T10608 */
1403
+ updated: [];
1404
+ /** Total number of live rows/entities affected. @task T10608 */
1405
+ affectedCount: number;
1406
+ /** Structured partial-success/preflight warnings. @task T10608 */
1407
+ mutationWarnings: TaskMutationWarning[];
1408
+ /** Standard dry-run/preflight projection. @task T10608 */
1409
+ dryRunSummary?: TaskMutationDryRunSummary;
944
1410
  }
945
1411
  export interface TasksArchiveQueryParams {
946
1412
  taskId?: string;
@@ -1023,6 +1489,8 @@ export interface TasksSagaCreateParams {
1023
1489
  description?: string;
1024
1490
  /** Pipe-separated acceptance criteria. */
1025
1491
  acceptance?: string[];
1492
+ /** Validate and preview the Saga without writing rows. */
1493
+ dryRun?: boolean;
1026
1494
  }
1027
1495
  /**
1028
1496
  * Result of `tasks.saga.create` — the newly created Saga task.
@@ -1031,12 +1499,22 @@ export interface TasksSagaCreateParams {
1031
1499
  * @task T9521
1032
1500
  */
1033
1501
  export interface TasksSagaCreateResult {
1034
- /** The created task record (type=epic, labels includes 'saga'). */
1502
+ /** The created task record (type='saga'). */
1035
1503
  task: TaskRecord;
1504
+ /** True when this is a validation-only preview. */
1505
+ dryRun?: boolean;
1506
+ /** Number of Saga tasks that would be created by a successful dry-run. */
1507
+ wouldCreate?: number;
1508
+ /** Generic affected-entity count for dry-run projection. */
1509
+ wouldAffect?: number;
1510
+ /** Number of Saga specs validated during dry-run preflight. */
1511
+ validatedCount?: number;
1512
+ /** Number of rows durably inserted; always 0 for dry-run. */
1513
+ insertedCount?: number;
1036
1514
  }
1037
1515
  /** Params for `tasks.saga.add` — link an Epic to a Saga. */
1038
1516
  export interface TasksSagaAddParams {
1039
- /** Saga task ID (must have label='saga'). */
1517
+ /** Saga task ID (must have type='saga'). */
1040
1518
  sagaId: string;
1041
1519
  /** Epic task ID to link as a member. */
1042
1520
  epicId: string;
@@ -1150,7 +1628,7 @@ export interface TasksSagaMembersResult {
1150
1628
  * @see ADR-073-above-epic-naming.md §1.2 — invariant I5
1151
1629
  */
1152
1630
  export interface TasksSagaRepairParams {
1153
- /** Saga task ID (must have `label='saga'`). */
1631
+ /** Saga task ID (must have type='saga'). */
1154
1632
  sagaId: string;
1155
1633
  }
1156
1634
  /**
@@ -1177,6 +1655,70 @@ export interface TasksSagaRepairResult {
1177
1655
  /** Free-form notes the CLI renderer can surface alongside the result. */
1178
1656
  note?: string;
1179
1657
  }
1658
+ /**
1659
+ * Params for `tasks.saga.migrate-containment` — migrate parent_id-based Saga
1660
+ * membership to `task_relations.type='groups'` (ADR-073 §1.2 invariant I5).
1661
+ *
1662
+ * Converts Epics whose `parent_id` points to a `type='saga'` task into
1663
+ * proper `groups` relations. Non-Epic tasks with Saga parents are documented
1664
+ * as conflicts requiring manual resolution.
1665
+ *
1666
+ * @task T10637
1667
+ * @see ADR-073-above-epic-naming.md §1.2 — invariant I5
1668
+ */
1669
+ export interface TasksSagaMigrateContainmentParams {
1670
+ /** Specific Saga ID to migrate. When omitted, migrates ALL sagas. */
1671
+ sagaId?: string;
1672
+ /** Dry-run mode: scan only, no mutations performed. */
1673
+ dryRun?: boolean;
1674
+ }
1675
+ /**
1676
+ * A single Epic that was migrated from parent_id to groups relation.
1677
+ *
1678
+ * @task T10637
1679
+ */
1680
+ export interface TasksSagaMigratedEpic {
1681
+ epicId: string;
1682
+ sagaId: string;
1683
+ oldParentId: string | null;
1684
+ groupsRelation: {
1685
+ from: string;
1686
+ to: string;
1687
+ type: 'groups';
1688
+ };
1689
+ }
1690
+ /**
1691
+ * A task (non-Epic) with a Saga parent — cannot be auto-migrated.
1692
+ *
1693
+ * @task T10637
1694
+ */
1695
+ export interface TasksSagaContainmentConflict {
1696
+ taskId: string;
1697
+ sagaId: string;
1698
+ taskType: string;
1699
+ taskTitle: string;
1700
+ reason: string;
1701
+ }
1702
+ /**
1703
+ * Result of `tasks.saga.migrate-containment` — reports every Epic migrated
1704
+ * and every non-Epic conflict that needs manual resolution.
1705
+ *
1706
+ * @task T10637
1707
+ */
1708
+ export interface TasksSagaMigrateContainmentResult {
1709
+ /** Total sagas scanned. */
1710
+ sagasScanned: number;
1711
+ /** Number of Epics successfully migrated. */
1712
+ migrated: number;
1713
+ /** Number of already-correct Epics skipped (idempotent no-op). */
1714
+ skipped: number;
1715
+ /** Detailed list of migrated Epics. */
1716
+ migratedEpics: TasksSagaMigratedEpic[];
1717
+ /** Non-Epic tasks with Saga parents — need manual resolution. */
1718
+ conflicts: TasksSagaContainmentConflict[];
1719
+ /** Whether this was a dry run (no mutations). */
1720
+ dryRun: boolean;
1721
+ }
1180
1722
  /**
1181
1723
  * Per-saga reconciliation action returned by `tasks.saga.reconcile`.
1182
1724
  *
@@ -1195,7 +1737,7 @@ export type TasksSagaReconcileAction = 'close' | 'no-op' | 'blocked' | 'error';
1195
1737
  export interface TasksSagaReconcileParams {
1196
1738
  /**
1197
1739
  * Optional single saga to reconcile. When omitted, the verb walks every
1198
- * saga returned by `taskList({ type: 'epic', label: 'saga' })`.
1740
+ * saga returned by `taskList({ type: 'saga' })`.
1199
1741
  */
1200
1742
  sagaId?: string;
1201
1743
  /**
@@ -1296,12 +1838,20 @@ export type TasksOps = {
1296
1838
  readonly tree: readonly [TasksTreeDispatchParams, TasksTreeDispatchResult];
1297
1839
  readonly blockers: readonly [TasksBlockersQueryParams, TasksBlockersQueryResult];
1298
1840
  readonly depends: readonly [TasksDependsParams, TasksDependsResult];
1841
+ readonly slice: readonly [TasksSliceParams, TasksSliceResult];
1299
1842
  readonly 'deps.validate': readonly [TasksDepsValidateParams, TasksDepsValidateResult];
1300
1843
  readonly 'deps.tree': readonly [TasksDepsTreeParams, TasksDepsTreeResult];
1301
1844
  readonly analyze: readonly [TasksAnalyzeQueryParams, TasksAnalyzeQueryResult];
1302
1845
  readonly impact: readonly [TasksImpactParams, TasksImpactResult];
1303
1846
  readonly next: readonly [TasksNextQueryParams, TasksNextQueryResult];
1304
1847
  readonly plan: readonly [TasksPlanParams, TasksPlanResult];
1848
+ readonly 'completion.list': readonly [CompletionListParams, CompletionListResult];
1849
+ readonly 'completion.evaluate': readonly [CompletionEvaluateParams, CompletionEvaluateResult];
1850
+ readonly 'completion.explain': readonly [CompletionExplainParams, CompletionExplainResult];
1851
+ readonly 'projection.repair': readonly [
1852
+ CompletionProjectionRepairParams,
1853
+ CompletionProjectionRepairResult
1854
+ ];
1305
1855
  readonly relates: readonly [TasksRelatesParams, TasksRelatesResult];
1306
1856
  readonly 'complexity.estimate': readonly [
1307
1857
  TasksComplexityEstimateParams,
@@ -1311,6 +1861,7 @@ export type TasksOps = {
1311
1861
  readonly current: readonly [TasksCurrentParams, TasksCurrentResult];
1312
1862
  readonly 'label.list': readonly [TasksLabelListParams, TasksLabelListResult];
1313
1863
  readonly 'sync.links': readonly [TasksSyncLinksParams, TasksSyncLinksResult];
1864
+ readonly context: readonly [TasksContextParams, TasksContextResult];
1314
1865
  readonly add: readonly [TasksAddParams, TasksAddResult];
1315
1866
  readonly 'add-batch': readonly [TasksAddBatchParams, TasksAddBatchResult];
1316
1867
  readonly update: readonly [TasksUpdateQueryParams, TasksUpdateQueryResult];
@@ -1322,6 +1873,7 @@ export type TasksOps = {
1322
1873
  readonly reparent: readonly [TasksReparentQueryParams, TasksReparentDispatchResult];
1323
1874
  readonly reorder: readonly [TasksReorderQueryParams, TasksReorderDispatchResult];
1324
1875
  readonly 'relates.add': readonly [TasksRelatesAddParams, TasksRelatesAddResult];
1876
+ readonly 'relates.add-batch': readonly [TasksRelatesAddBatchParams, TasksRelatesAddBatchResult];
1325
1877
  readonly 'relates.remove': readonly [TasksRelatesRemoveParams, TasksRelatesRemoveResult];
1326
1878
  readonly start: readonly [TasksStartQueryParams, TasksStartQueryResult];
1327
1879
  readonly stop: readonly [TasksStopQueryParams, TasksStopQueryResult];
@@ -1339,6 +1891,11 @@ export type TasksOps = {
1339
1891
  readonly 'saga.repair': readonly [TasksSagaRepairParams, TasksSagaRepairResult];
1340
1892
  /** T10121 — idempotent cron-safe auto-close repair (supersedes T10098 scope). */
1341
1893
  readonly 'saga.reconcile': readonly [TasksSagaReconcileParams, TasksSagaReconcileResult];
1894
+ /** T10637 — migrate parent_id-based Saga membership to groups relations. */
1895
+ readonly 'saga.migrate-containment': readonly [
1896
+ TasksSagaMigrateContainmentParams,
1897
+ TasksSagaMigrateContainmentResult
1898
+ ];
1342
1899
  };
1343
1900
  /**
1344
1901
  * Per-task entry inside a `tasks.add-batch` payload.
@@ -1357,7 +1914,7 @@ export interface TasksAddBatchEntry {
1357
1914
  description?: string;
1358
1915
  /** Parent task ID (makes this task a subtask). */
1359
1916
  parent?: string;
1360
- /** Comma-separated dependency task IDs. */
1917
+ /** Dependency task IDs as a JSON array. */
1361
1918
  depends?: string[];
1362
1919
  /** Task priority (low | medium | high | critical). */
1363
1920
  priority?: string;
@@ -1365,7 +1922,7 @@ export interface TasksAddBatchEntry {
1365
1922
  labels?: string[];
1366
1923
  /** Task type (saga | epic | task | subtask). */
1367
1924
  type?: TaskType;
1368
- /** Pipe-separated acceptance criteria, normalized to string[]. */
1925
+ /** Acceptance criteria as a JSON array; pipe-delimited strings are not canonical. */
1369
1926
  acceptance?: string[];
1370
1927
  /** Phase slug to assign the task to. */
1371
1928
  phase?: string;