agentic-orchestrator 0.1.25 → 0.1.26

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 (177) hide show
  1. package/agentic/orchestrator/defaults/policy.defaults.yaml +1 -0
  2. package/agentic/orchestrator/policy.yaml +1 -0
  3. package/agentic/orchestrator/schemas/policy.schema.json +4 -0
  4. package/agentic/orchestrator/schemas/policy.user.schema.json +4 -0
  5. package/apps/control-plane/src/application/services/activity-monitor-service.ts +42 -0
  6. package/apps/control-plane/src/application/services/collision-queue-service.ts +48 -0
  7. package/apps/control-plane/src/application/services/cost-tracking-service.ts +80 -0
  8. package/apps/control-plane/src/application/services/feature-deletion-service.ts +57 -0
  9. package/apps/control-plane/src/application/services/feature-lifecycle-service.ts +65 -0
  10. package/apps/control-plane/src/application/services/feature-state-service.ts +87 -0
  11. package/apps/control-plane/src/application/services/gate-selection-service.ts +28 -0
  12. package/apps/control-plane/src/application/services/gate-service.ts +148 -0
  13. package/apps/control-plane/src/application/services/issue-tracker-service.ts +28 -0
  14. package/apps/control-plane/src/application/services/lock-service.ts +88 -0
  15. package/apps/control-plane/src/application/services/merge-service.ts +63 -0
  16. package/apps/control-plane/src/application/services/notifier-service.ts +70 -0
  17. package/apps/control-plane/src/application/services/patch-service.ts +95 -0
  18. package/apps/control-plane/src/application/services/performance-analytics-service.ts +90 -0
  19. package/apps/control-plane/src/application/services/plan-service.ts +184 -0
  20. package/apps/control-plane/src/application/services/pr-monitor-service.ts +58 -0
  21. package/apps/control-plane/src/application/services/qa-index-service.ts +68 -0
  22. package/apps/control-plane/src/application/services/reactions-service.ts +77 -0
  23. package/apps/control-plane/src/application/services/reporting-service.ts +79 -0
  24. package/apps/control-plane/src/application/services/run-lease-service.ts +79 -0
  25. package/apps/control-plane/src/application/tools/tool-router.ts +76 -0
  26. package/apps/control-plane/src/mcp/tool-runtime.ts +4 -0
  27. package/apps/control-plane/src/providers/providers.ts +96 -0
  28. package/apps/control-plane/src/providers/worker-provider-factory.ts +4 -0
  29. package/apps/control-plane/src/supervisor/build-wave-executor.ts +4 -0
  30. package/apps/control-plane/src/supervisor/planning-wave-executor.ts +4 -0
  31. package/apps/control-plane/src/supervisor/qa-wave-executor.ts +4 -0
  32. package/apps/control-plane/src/supervisor/run-coordinator.ts +4 -0
  33. package/apps/control-plane/src/supervisor/runtime.ts +4 -0
  34. package/apps/control-plane/src/supervisor/session-orchestrator.ts +4 -0
  35. package/apps/control-plane/test/dashboard-api.integration.spec.ts +310 -1
  36. package/apps/control-plane/test/dashboard-client.spec.ts +136 -1
  37. package/apps/control-plane/test/dashboard-live-feed.spec.ts +153 -0
  38. package/apps/control-plane/test/dashboard-ui-utils.spec.ts +132 -0
  39. package/apps/control-plane/test/mcp.spec.ts +96 -0
  40. package/apps/control-plane/test/tool-runtime.spec.ts +68 -0
  41. package/config/agentic/orchestrator/policy.yaml +1 -0
  42. package/dist/apps/control-plane/application/services/activity-monitor-service.d.ts +42 -0
  43. package/dist/apps/control-plane/application/services/activity-monitor-service.js +42 -0
  44. package/dist/apps/control-plane/application/services/activity-monitor-service.js.map +1 -1
  45. package/dist/apps/control-plane/application/services/collision-queue-service.d.ts +48 -0
  46. package/dist/apps/control-plane/application/services/collision-queue-service.js +48 -0
  47. package/dist/apps/control-plane/application/services/collision-queue-service.js.map +1 -1
  48. package/dist/apps/control-plane/application/services/cost-tracking-service.d.ts +79 -0
  49. package/dist/apps/control-plane/application/services/cost-tracking-service.js +76 -0
  50. package/dist/apps/control-plane/application/services/cost-tracking-service.js.map +1 -1
  51. package/dist/apps/control-plane/application/services/feature-deletion-service.d.ts +57 -0
  52. package/dist/apps/control-plane/application/services/feature-deletion-service.js +57 -0
  53. package/dist/apps/control-plane/application/services/feature-deletion-service.js.map +1 -1
  54. package/dist/apps/control-plane/application/services/feature-lifecycle-service.d.ts +64 -0
  55. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js +61 -0
  56. package/dist/apps/control-plane/application/services/feature-lifecycle-service.js.map +1 -1
  57. package/dist/apps/control-plane/application/services/feature-state-service.d.ts +86 -0
  58. package/dist/apps/control-plane/application/services/feature-state-service.js +83 -0
  59. package/dist/apps/control-plane/application/services/feature-state-service.js.map +1 -1
  60. package/dist/apps/control-plane/application/services/gate-selection-service.d.ts +28 -0
  61. package/dist/apps/control-plane/application/services/gate-selection-service.js +28 -0
  62. package/dist/apps/control-plane/application/services/gate-selection-service.js.map +1 -1
  63. package/dist/apps/control-plane/application/services/gate-service.d.ts +148 -0
  64. package/dist/apps/control-plane/application/services/gate-service.js +120 -0
  65. package/dist/apps/control-plane/application/services/gate-service.js.map +1 -1
  66. package/dist/apps/control-plane/application/services/issue-tracker-service.d.ts +28 -0
  67. package/dist/apps/control-plane/application/services/issue-tracker-service.js +28 -0
  68. package/dist/apps/control-plane/application/services/issue-tracker-service.js.map +1 -1
  69. package/dist/apps/control-plane/application/services/lock-service.d.ts +88 -0
  70. package/dist/apps/control-plane/application/services/lock-service.js +64 -0
  71. package/dist/apps/control-plane/application/services/lock-service.js.map +1 -1
  72. package/dist/apps/control-plane/application/services/merge-service.d.ts +62 -0
  73. package/dist/apps/control-plane/application/services/merge-service.js +59 -0
  74. package/dist/apps/control-plane/application/services/merge-service.js.map +1 -1
  75. package/dist/apps/control-plane/application/services/notifier-service.d.ts +70 -0
  76. package/dist/apps/control-plane/application/services/notifier-service.js +70 -0
  77. package/dist/apps/control-plane/application/services/notifier-service.js.map +1 -1
  78. package/dist/apps/control-plane/application/services/patch-service.d.ts +94 -0
  79. package/dist/apps/control-plane/application/services/patch-service.js +91 -0
  80. package/dist/apps/control-plane/application/services/patch-service.js.map +1 -1
  81. package/dist/apps/control-plane/application/services/performance-analytics-service.d.ts +89 -0
  82. package/dist/apps/control-plane/application/services/performance-analytics-service.js +86 -0
  83. package/dist/apps/control-plane/application/services/performance-analytics-service.js.map +1 -1
  84. package/dist/apps/control-plane/application/services/plan-service.d.ts +287 -0
  85. package/dist/apps/control-plane/application/services/plan-service.js +207 -0
  86. package/dist/apps/control-plane/application/services/plan-service.js.map +1 -1
  87. package/dist/apps/control-plane/application/services/pr-monitor-service.d.ts +58 -0
  88. package/dist/apps/control-plane/application/services/pr-monitor-service.js +58 -0
  89. package/dist/apps/control-plane/application/services/pr-monitor-service.js.map +1 -1
  90. package/dist/apps/control-plane/application/services/qa-index-service.d.ts +67 -0
  91. package/dist/apps/control-plane/application/services/qa-index-service.js +64 -0
  92. package/dist/apps/control-plane/application/services/qa-index-service.js.map +1 -1
  93. package/dist/apps/control-plane/application/services/reactions-service.d.ts +76 -0
  94. package/dist/apps/control-plane/application/services/reactions-service.js +73 -0
  95. package/dist/apps/control-plane/application/services/reactions-service.js.map +1 -1
  96. package/dist/apps/control-plane/application/services/reporting-service.d.ts +78 -0
  97. package/dist/apps/control-plane/application/services/reporting-service.js +75 -0
  98. package/dist/apps/control-plane/application/services/reporting-service.js.map +1 -1
  99. package/dist/apps/control-plane/application/services/run-lease-service.d.ts +79 -0
  100. package/dist/apps/control-plane/application/services/run-lease-service.js +79 -0
  101. package/dist/apps/control-plane/application/services/run-lease-service.js.map +1 -1
  102. package/dist/apps/control-plane/application/tools/tool-router.d.ts +76 -0
  103. package/dist/apps/control-plane/application/tools/tool-router.js +62 -0
  104. package/dist/apps/control-plane/application/tools/tool-router.js.map +1 -1
  105. package/dist/apps/control-plane/mcp/tool-runtime.d.ts +3 -0
  106. package/dist/apps/control-plane/mcp/tool-runtime.js +3 -0
  107. package/dist/apps/control-plane/mcp/tool-runtime.js.map +1 -1
  108. package/dist/apps/control-plane/providers/providers.d.ts +88 -0
  109. package/dist/apps/control-plane/providers/providers.js.map +1 -1
  110. package/dist/apps/control-plane/providers/worker-provider-factory.d.ts +3 -0
  111. package/dist/apps/control-plane/providers/worker-provider-factory.js.map +1 -1
  112. package/dist/apps/control-plane/supervisor/build-wave-executor.d.ts +3 -0
  113. package/dist/apps/control-plane/supervisor/build-wave-executor.js +3 -0
  114. package/dist/apps/control-plane/supervisor/build-wave-executor.js.map +1 -1
  115. package/dist/apps/control-plane/supervisor/planning-wave-executor.d.ts +3 -0
  116. package/dist/apps/control-plane/supervisor/planning-wave-executor.js +3 -0
  117. package/dist/apps/control-plane/supervisor/planning-wave-executor.js.map +1 -1
  118. package/dist/apps/control-plane/supervisor/qa-wave-executor.d.ts +3 -0
  119. package/dist/apps/control-plane/supervisor/qa-wave-executor.js +3 -0
  120. package/dist/apps/control-plane/supervisor/qa-wave-executor.js.map +1 -1
  121. package/dist/apps/control-plane/supervisor/run-coordinator.d.ts +3 -0
  122. package/dist/apps/control-plane/supervisor/run-coordinator.js +3 -0
  123. package/dist/apps/control-plane/supervisor/run-coordinator.js.map +1 -1
  124. package/dist/apps/control-plane/supervisor/runtime.d.ts +3 -0
  125. package/dist/apps/control-plane/supervisor/runtime.js +3 -0
  126. package/dist/apps/control-plane/supervisor/runtime.js.map +1 -1
  127. package/dist/apps/control-plane/supervisor/session-orchestrator.d.ts +3 -0
  128. package/dist/apps/control-plane/supervisor/session-orchestrator.js +3 -0
  129. package/dist/apps/control-plane/supervisor/session-orchestrator.js.map +1 -1
  130. package/package.json +1 -1
  131. package/packages/web-dashboard/src/app/analytics/page.tsx +451 -0
  132. package/packages/web-dashboard/src/app/api/analytics/route.ts +62 -0
  133. package/packages/web-dashboard/src/app/api/collisions/route.ts +63 -0
  134. package/packages/web-dashboard/src/app/api/features/[id]/cost/route.ts +29 -0
  135. package/packages/web-dashboard/src/app/api/features/[id]/review-brief/route.ts +31 -0
  136. package/packages/web-dashboard/src/app/api/features/[id]/route.ts +5 -8
  137. package/packages/web-dashboard/src/app/api/features/[id]/test-index/route.ts +31 -0
  138. package/packages/web-dashboard/src/app/api/flaky/route.ts +20 -0
  139. package/packages/web-dashboard/src/app/api/policy/budget/route.ts +31 -0
  140. package/packages/web-dashboard/src/app/api/run/route.ts +162 -0
  141. package/packages/web-dashboard/src/app/api/status/route.ts +2 -5
  142. package/packages/web-dashboard/src/app/feature/[id]/page.tsx +112 -0
  143. package/packages/web-dashboard/src/app/page.tsx +379 -77
  144. package/packages/web-dashboard/src/components/agent-pipeline-stepper.tsx +100 -0
  145. package/packages/web-dashboard/src/components/dependency-chains.tsx +58 -0
  146. package/packages/web-dashboard/src/components/detail-panel.tsx +215 -5
  147. package/packages/web-dashboard/src/components/feature-card.tsx +5 -0
  148. package/packages/web-dashboard/src/components/feature-cost-panel.tsx +66 -0
  149. package/packages/web-dashboard/src/components/feature-list-view.tsx +336 -0
  150. package/packages/web-dashboard/src/components/gate-step-drilldown.tsx +92 -0
  151. package/packages/web-dashboard/src/components/kanban-board.tsx +3 -0
  152. package/packages/web-dashboard/src/components/live-event-feed.tsx +60 -0
  153. package/packages/web-dashboard/src/components/lock-resource-map.tsx +73 -0
  154. package/packages/web-dashboard/src/components/plan-revision-timeline.tsx +55 -0
  155. package/packages/web-dashboard/src/components/plan-risk-annotations.tsx +63 -0
  156. package/packages/web-dashboard/src/components/plan-scope-tree.tsx +285 -0
  157. package/packages/web-dashboard/src/components/qa-coverage-map.tsx +174 -0
  158. package/packages/web-dashboard/src/components/quick-launch-panel.tsx +70 -0
  159. package/packages/web-dashboard/src/components/review-brief-panel.tsx +75 -0
  160. package/packages/web-dashboard/src/components/run-health-panel.tsx +85 -0
  161. package/packages/web-dashboard/src/components/summary-bar.tsx +59 -2
  162. package/packages/web-dashboard/src/components/verification-signals.tsx +167 -0
  163. package/packages/web-dashboard/src/lib/analytics-utils.ts +3 -0
  164. package/packages/web-dashboard/src/lib/aop-client.ts +510 -11
  165. package/packages/web-dashboard/src/lib/api-envelope.ts +48 -0
  166. package/packages/web-dashboard/src/lib/authz-adapter.ts +33 -0
  167. package/packages/web-dashboard/src/lib/dashboard-utils.ts +304 -0
  168. package/packages/web-dashboard/src/lib/live-feed.ts +218 -0
  169. package/packages/web-dashboard/src/lib/policy-reader.ts +22 -0
  170. package/packages/web-dashboard/src/lib/types.ts +114 -0
  171. package/packages/web-dashboard/src/styles/dashboard.module.css +341 -1
  172. package/spec-files/{outstanding → completed}/agentic_orchestrator_dashboard_advanced_ux_spec.md +1 -1
  173. package/spec-files/outstanding/agentic_orchestrator_evidence_integrity_doctor_spec.md +561 -0
  174. package/spec-files/outstanding/agentic_orchestrator_kernel_simplification_spec.md +834 -0
  175. package/spec-files/outstanding/agentic_orchestrator_observability_integrity_diagnostics_spec.md +12 -5
  176. package/spec-files/outstanding/agentic_orchestrator_observability_replay_spec.md +442 -0
  177. package/spec-files/progress.md +174 -1
@@ -54,21 +54,98 @@ function deriveStatusFromGateResult(
54
54
  return currentStatus;
55
55
  }
56
56
 
57
+ /**
58
+ * Port interface for gate operations.
59
+ *
60
+ * ## Contract
61
+ * Implementations must ensure:
62
+ * - Access to gates configuration and policy
63
+ * - State read/update with version guards
64
+ * - Path resolution for worktrees, logs, and evidence
65
+ *
66
+ * ## Error Handling
67
+ * All methods throw normalized errors with stable error codes.
68
+ */
57
69
  export interface GateServicePort {
70
+ /** Returns repository root path. */
58
71
  getRepoRoot(): string;
72
+ /** Returns gates configuration. */
59
73
  getGatesConfig(): AnyRecord;
74
+ /** Returns policy snapshot. */
60
75
  getPolicySnapshot(): AnyRecord;
76
+ /**
77
+ * Reads feature state.
78
+ * @throws FEATURE_NOT_FOUND - if state doesn't exist
79
+ */
61
80
  readState(featureId: string): Promise<{ frontMatter: AnyRecord }>;
81
+ /**
82
+ * Updates feature state with version guard.
83
+ * @param featureId - feature identifier
84
+ * @param expectedVersion - expected version (null = no check)
85
+ * @param updater - function returning updated state
86
+ */
62
87
  updateState(
63
88
  featureId: string,
64
89
  expectedVersion: number | null,
65
90
  updater: StateUpdater,
66
91
  ): Promise<AnyRecord>;
92
+ /** Returns absolute path to feature worktree. */
67
93
  worktreePath(featureId: string): string;
94
+ /** Returns absolute path to feature logs directory. */
68
95
  logsPath(featureId: string): string;
96
+ /** Returns absolute path to feature evidence directory. */
69
97
  evidencePath(featureId: string): string;
70
98
  }
71
99
 
100
+ /**
101
+ * Manages gate execution, evidence collection, and threshold enforcement.
102
+ *
103
+ * ## Responsibilities
104
+ * - Execute gate profiles (fast/full/merge) with command interpolation
105
+ * - Collect logs and evidence artifacts
106
+ * - Parse coverage reports and enforce thresholds
107
+ * - Update feature state with gate results
108
+ * - Transition status based on gate outcomes
109
+ *
110
+ * ## Dependencies
111
+ * Depends on {@link GateServicePort} for:
112
+ * - Gates configuration and policy access
113
+ * - State updates and file operations
114
+ * - Worktree and evidence path resolution
115
+ *
116
+ * ## Key Methods
117
+ * - `gatesRun()` - execute gate profile with evidence collection
118
+ * - `gatesList()` - list available gate profiles
119
+ * - `evidenceLatest()` - retrieve latest evidence summary
120
+ * - `gateProfileAndMode()` - resolve profile/mode configuration
121
+ *
122
+ * ## Error Conditions
123
+ * - GATE_FAILED - gate execution failed or thresholds not met
124
+ * - INVALID_ARGUMENT - unknown profile or mode
125
+ * - FILE_NOT_FOUND - missing evidence or coverage files
126
+ *
127
+ * ## Gate Lifecycle
128
+ * 1. Select profile and mode based on feature state
129
+ * 2. Interpolate commands with feature context
130
+ * 3. Execute steps (sequential or parallel)
131
+ * 4. Collect evidence and parse coverage
132
+ * 5. Enforce thresholds (minimums and targets)
133
+ * 6. Update state and transition status
134
+ *
135
+ * @example
136
+ * ```typescript
137
+ * const gateService = new GateService(port);
138
+ *
139
+ * // Execute fast gate profile
140
+ * await gateService.gatesRun('my_feature', 'fast', 'fast', null);
141
+ *
142
+ * // Get latest evidence
143
+ * const evidence = await gateService.evidenceLatest('my_feature');
144
+ * ```
145
+ *
146
+ * ## Thread Safety
147
+ * State updates are atomic via version guards.
148
+ */
72
149
  export class GateService {
73
150
  private readonly port: GateServicePort;
74
151
  private readonly gateSelectionService: GateSelectionService;
@@ -78,6 +155,21 @@ export class GateService {
78
155
  this.gateSelectionService = new GateSelectionService(port);
79
156
  }
80
157
 
158
+ /**
159
+ * Lists available gate profiles or returns specific profile configuration.
160
+ *
161
+ * @param profileName - optional profile name to retrieve
162
+ * @returns Profile configuration or all profiles
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * // List all profiles
167
+ * const all = gateService.gatesList();
168
+ *
169
+ * // Get specific profile
170
+ * const fast = gateService.gatesList('fast');
171
+ * ```
172
+ */
81
173
  gatesList(profileName: string | null = null): { data: AnyRecord } {
82
174
  const gatesConfig = this.port.getGatesConfig();
83
175
  if (profileName) {
@@ -96,10 +188,50 @@ export class GateService {
96
188
  };
97
189
  }
98
190
 
191
+ /**
192
+ * Resolves gate profile and mode configuration.
193
+ *
194
+ * @param profileName - profile identifier
195
+ * @param mode - mode identifier
196
+ * @returns Resolved profile/mode configuration
197
+ * @throws INVALID_ARGUMENT - unknown profile or mode
198
+ *
199
+ * @example
200
+ * ```typescript
201
+ * const config = gateService.gateProfileAndMode('fast', 'fast');
202
+ * ```
203
+ */
99
204
  gateProfileAndMode(profileName: string, mode: string): AnyRecord {
100
205
  return this.gateSelectionService.resolveProfileAndMode(profileName, mode);
101
206
  }
102
207
 
208
+ /**
209
+ * Executes gate profile with evidence collection and threshold enforcement.
210
+ *
211
+ * Workflow:
212
+ * 1. Resolve profile/mode from state or explicit parameters
213
+ * 2. Interpolate commands with feature context
214
+ * 3. Execute steps (parallel groups or sequential)
215
+ * 4. Collect logs and evidence artifacts
216
+ * 5. Parse coverage and enforce thresholds
217
+ * 6. Update state with results and transition status
218
+ *
219
+ * @param featureId - feature identifier
220
+ * @param profileName - gate profile (null = auto-select from state)
221
+ * @param mode - gate mode (fast/full/merge)
222
+ * @returns Gate execution results with coverage and evidence
223
+ * @throws GATE_FAILED - execution failed or thresholds not met
224
+ * @throws INVALID_ARGUMENT - unknown profile or mode
225
+ *
226
+ * @example
227
+ * ```typescript
228
+ * // Auto-select profile from state
229
+ * await gateService.gatesRun('my_feature', null, 'fast');
230
+ *
231
+ * // Explicit profile
232
+ * await gateService.gatesRun('my_feature', 'fast', 'fast');
233
+ * ```
234
+ */
103
235
  async gatesRun(
104
236
  featureId: string,
105
237
  profileName: string | null,
@@ -236,6 +368,22 @@ export class GateService {
236
368
  };
237
369
  }
238
370
 
371
+ /**
372
+ * Retrieves latest evidence summary for a feature.
373
+ *
374
+ * Returns most recent gate execution evidence including logs,
375
+ * coverage reports, and artifact paths.
376
+ *
377
+ * @param featureId - feature identifier
378
+ * @returns Evidence summary with paths and metadata
379
+ * @throws FILE_NOT_FOUND - no evidence exists
380
+ *
381
+ * @example
382
+ * ```typescript
383
+ * const evidence = await gateService.evidenceLatest('my_feature');
384
+ * console.log(evidence.data.coverage);
385
+ * ```
386
+ */
239
387
  async evidenceLatest(
240
388
  featureId: string,
241
389
  ): Promise<{ data: { feature_id: string; latest: AnyRecord | null; path?: string } }> {
@@ -83,6 +83,16 @@ function tryParseJson(value: string): Record<string, unknown> | null {
83
83
  }
84
84
  }
85
85
 
86
+ /**
87
+ * GitHub issue tracker implementation.
88
+ *
89
+ * @example
90
+ * ```typescript
91
+ * const tracker = new GitHubIssueTracker({ repo: 'owner/repo' });
92
+ * const issue = await tracker.getIssue('123');
93
+ * await tracker.updateIssueStatus('123', 'closed');
94
+ * ```
95
+ */
86
96
  export class GitHubIssueTracker implements IssueTracker {
87
97
  private readonly repo: string | undefined;
88
98
  private readonly ghRunner: GhRunner;
@@ -194,6 +204,15 @@ function mapDefaultJiraTransition(status: string): string {
194
204
  }
195
205
 
196
206
  // --- Linear adapter (GraphQL HTTP) ---
207
+ /**
208
+ * Linear issue tracker implementation.
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * const tracker = new LinearIssueTracker({ api_key: 'lin_...' });
213
+ * const issue = await tracker.getIssue('PROJ-123');
214
+ * ```
215
+ */
197
216
  export class LinearIssueTracker implements IssueTracker {
198
217
  private readonly token: string;
199
218
  private readonly baseUrl: string;
@@ -343,6 +362,15 @@ function toJiraDescription(value: unknown): string {
343
362
  }
344
363
 
345
364
  // --- Jira adapter (REST HTTP) ---
365
+ /**
366
+ * Jira issue tracker implementation.
367
+ *
368
+ * @example
369
+ * ```typescript
370
+ * const tracker = new JiraIssueTracker({ base_url: 'https://company.atlassian.net', api_token: '...' });
371
+ * const issue = await tracker.getIssue('PROJ-123');
372
+ * ```
373
+ */
346
374
  export class JiraIssueTracker implements IssueTracker {
347
375
  private readonly baseUrl: string;
348
376
  private readonly token: string;
@@ -18,17 +18,41 @@ interface CollisionQueueDrivePort {
18
18
  }>;
19
19
  }
20
20
 
21
+ /**
22
+ * Port interface for lock operations.
23
+ *
24
+ * ## Contract
25
+ * Implementations must ensure:
26
+ * - Atomic lock acquisition and release via index lock
27
+ * - Lease TTL enforcement with stale lock reclamation
28
+ * - State updates reflect lock ownership changes
29
+ *
30
+ * ## Error Handling
31
+ * All methods throw normalized errors with stable error codes.
32
+ */
21
33
  export interface LockServicePort {
34
+ /** Executes an operation with index-level lock held. */
22
35
  withIndexLock<T>(operation: () => Promise<T>): Promise<T>;
36
+ /** Reads the global feature index. */
23
37
  readIndex(): Promise<AnyRecord>;
38
+ /** Writes the global feature index atomically. */
24
39
  writeIndex(index: AnyRecord): Promise<void>;
40
+ /**
41
+ * Updates feature state with version guard.
42
+ * @param featureId - feature identifier
43
+ * @param expectedVersion - expected version (null = no check)
44
+ * @param updater - function returning updated state
45
+ */
25
46
  updateState(
26
47
  featureId: string,
27
48
  expectedVersion: number | null,
28
49
  updater: StateUpdater,
29
50
  ): Promise<AnyRecord>;
51
+ /** Returns absolute path to feature state file. */
30
52
  statePath(featureId: string): string;
53
+ /** Returns current policy snapshot. */
31
54
  getPolicySnapshot(): AnyRecord;
55
+ /** Optional collision queue service for re-drive after lock release. */
32
56
  collisionQueueService?: CollisionQueueDrivePort;
33
57
  }
34
58
 
@@ -40,6 +64,42 @@ function sleep(ms: number): Promise<void> {
40
64
  return new Promise((resolve) => setTimeout(resolve, ms));
41
65
  }
42
66
 
67
+ /**
68
+ * Manages resource lock acquisition, renewal, and release.
69
+ *
70
+ * ## Responsibilities
71
+ * - Acquire resource locks with wait/backoff behavior
72
+ * - Enforce lease TTL and reclaim stale locks
73
+ * - Update feature state to reflect lock ownership
74
+ * - Trigger collision queue re-drive on lock release
75
+ *
76
+ * ## Dependencies
77
+ * - {@link LockServicePort} - for index/state operations and policy access
78
+ *
79
+ * ## Key Methods
80
+ * - `locksAcquire()` - acquire resource lock with wait/backoff
81
+ * - `locksRelease()` - release resource lock and trigger re-drive
82
+ *
83
+ * ## Error Conditions
84
+ * - INVALID_ARGUMENT - unknown resource or missing featureId
85
+ * - LOCK_CONFLICT - lock held by another feature (fail mode)
86
+ * - LOCK_TIMEOUT - wait timeout exceeded
87
+ *
88
+ * ## Thread Safety
89
+ * All lock operations are atomic via index-level lock.
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * // Acquire lock with default wait behavior
94
+ * await lockService.locksAcquire('openapi', 'my_feature', null);
95
+ *
96
+ * // Acquire with custom timeout
97
+ * await lockService.locksAcquire('db_migrations', 'my_feature', 60);
98
+ *
99
+ * // Release lock
100
+ * await lockService.locksRelease('openapi', 'my_feature');
101
+ * ```
102
+ */
43
103
  export class LockService {
44
104
  private readonly port: LockServicePort;
45
105
 
@@ -47,6 +107,17 @@ export class LockService {
47
107
  this.port = port;
48
108
  }
49
109
 
110
+ /**
111
+ * Acquires a resource lock for a feature with optional wait behavior.
112
+ *
113
+ * @param resource - resource identifier (must be in policy.locks.resources)
114
+ * @param featureId - feature requesting the lock
115
+ * @param waitTimeoutSeconds - max wait time (null = use policy default)
116
+ * @returns Success response with lease metadata
117
+ * @throws INVALID_ARGUMENT - unknown resource or missing featureId
118
+ * @throws LOCK_TIMEOUT - wait timeout exceeded
119
+ * @throws LOCK_HELD - lock held by another feature (fail behavior only)
120
+ */
50
121
  async locksAcquire(
51
122
  resource: string | null,
52
123
  featureId: string | null,
@@ -176,6 +247,23 @@ export class LockService {
176
247
  }
177
248
  }
178
249
 
250
+ /**
251
+ * Releases a resource lock held by a feature.
252
+ *
253
+ * Removes lock from index, updates feature state, and triggers
254
+ * collision queue re-drive to unblock waiting features.
255
+ *
256
+ * @param resource - resource identifier
257
+ * @param featureId - feature releasing the lock
258
+ * @returns Success response
259
+ * @throws INVALID_ARGUMENT - missing resource or featureId
260
+ * @throws LOCK_CONFLICT - lock held by another feature
261
+ *
262
+ * @example
263
+ * ```typescript
264
+ * await lockService.locksRelease('openapi', 'my_feature');
265
+ * ```
266
+ */
179
267
  async locksRelease(resource: string | null, featureId: string | null) {
180
268
  if (!resource || !featureId) {
181
269
  throw {
@@ -33,6 +33,10 @@ function asArray<T = unknown>(value: unknown): T[] {
33
33
  return Array.isArray(value) ? (value as T[]) : [];
34
34
  }
35
35
 
36
+ /**
37
+ * @fileoverview Merge promotion and branch management service.
38
+ */
39
+
36
40
  export interface MergeServicePort {
37
41
  getRepoRoot(): string;
38
42
  getPolicySnapshot(): AnyRecord;
@@ -50,6 +54,41 @@ export interface MergeServicePort {
50
54
  writeIndex(index: AnyRecord): Promise<void>;
51
55
  }
52
56
 
57
+ /**
58
+ * Manages merge promotion and branch lifecycle.
59
+ *
60
+ * ## Responsibilities
61
+ * - Validate merge readiness (gates passed, approval obtained)
62
+ * - Commit worktree changes
63
+ * - Merge feature branch to base
64
+ * - Clean up worktree and branch
65
+ * - Update index to reflect merge
66
+ *
67
+ * ## Dependencies
68
+ * Depends on {@link MergeServicePort} for:
69
+ * - State and index operations
70
+ * - Policy and worktree access
71
+ * - Lock release coordination
72
+ *
73
+ * ## Key Methods
74
+ * - `featureReadyToMerge()` - validate, commit, merge, and cleanup
75
+ *
76
+ * ## Error Conditions
77
+ * - MERGE_REQUIREMENTS_NOT_MET - gates not passed or approval missing
78
+ * - MERGE_CONFLICT - git merge failed
79
+ * - UNCOMMITTED_CHANGES - worktree has uncommitted changes
80
+ *
81
+ * ## Merge Requirements
82
+ * - All required gates must pass
83
+ * - Approval token must be valid (if required by policy)
84
+ * - No uncommitted changes in worktree
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const mergeService = new MergeService(port);
89
+ * await mergeService.featureReadyToMerge('my_feature', 'approve_abc123');
90
+ * ```
91
+ */
53
92
  export class MergeService {
54
93
  private readonly port: MergeServicePort;
55
94
 
@@ -99,6 +138,30 @@ export class MergeService {
99
138
  }
100
139
  }
101
140
 
141
+ /**
142
+ * Validates merge readiness, commits changes, merges to base, and cleans up.
143
+ *
144
+ * Full workflow:
145
+ * 1. Validate required gates passed
146
+ * 2. Verify approval token (if policy requires)
147
+ * 3. Commit worktree changes
148
+ * 4. Merge feature branch to base branch
149
+ * 5. Release held locks
150
+ * 6. Update index (move to merged, remove from active)
151
+ * 7. Schedule cleanup (worktree/branch removal per policy)
152
+ *
153
+ * @param featureId - feature identifier
154
+ * @param approvalToken - approval token (required if policy enforces)
155
+ * @returns Merge result with commit SHA and cleanup status
156
+ * @throws MERGE_REQUIREMENTS_NOT_MET - gates not passed or approval invalid
157
+ * @throws MERGE_CONFLICT - git merge failed
158
+ * @throws UNCOMMITTED_CHANGES - worktree has uncommitted changes
159
+ *
160
+ * @example
161
+ * ```typescript
162
+ * await mergeService.featureReadyToMerge('my_feature', 'approve_abc123');
163
+ * ```
164
+ */
102
165
  async featureReadyToMerge(
103
166
  featureId: string,
104
167
  commitMessage: string,
@@ -72,6 +72,15 @@ const EVENT_PRIORITY: Record<NotificationEvent, CanonicalPriority> = {
72
72
 
73
73
  const THROTTLE_WINDOW_MS = 5 * 60 * 1000; // 5 minutes
74
74
 
75
+ /**
76
+ * Desktop notification channel using notify-send.
77
+ *
78
+ * @example
79
+ * ```typescript
80
+ * const channel = new DesktopNotifierChannel();
81
+ * await channel.send(payload);
82
+ * ```
83
+ */
75
84
  export class DesktopNotifierChannel implements NotifierChannel {
76
85
  readonly name = 'desktop';
77
86
 
@@ -96,6 +105,15 @@ export class DesktopNotifierChannel implements NotifierChannel {
96
105
  }
97
106
  }
98
107
 
108
+ /**
109
+ * Slack notification channel using webhook.
110
+ *
111
+ * @example
112
+ * ```typescript
113
+ * const channel = new SlackNotifierChannel(webhookUrl, '#alerts');
114
+ * await channel.send(payload);
115
+ * ```
116
+ */
99
117
  export class SlackNotifierChannel implements NotifierChannel {
100
118
  readonly name = 'slack';
101
119
  private readonly webhookUrl: string;
@@ -139,6 +157,15 @@ export class SlackNotifierChannel implements NotifierChannel {
139
157
  }
140
158
  }
141
159
 
160
+ /**
161
+ * Generic webhook notification channel.
162
+ *
163
+ * @example
164
+ * ```typescript
165
+ * const channel = new WebhookNotifierChannel('https://example.com/webhook');
166
+ * await channel.send(payload);
167
+ * ```
168
+ */
142
169
  export class WebhookNotifierChannel implements NotifierChannel {
143
170
  readonly name = 'webhook';
144
171
  private readonly url: string;
@@ -159,6 +186,36 @@ export class WebhookNotifierChannel implements NotifierChannel {
159
186
  }
160
187
  }
161
188
 
189
+ /**
190
+ * Manages multi-channel notifications with priority routing.
191
+ *
192
+ * ## Responsibilities
193
+ * - Route notifications by priority (critical/warning/info)
194
+ * - Send to multiple channels (desktop/Slack/webhook)
195
+ * - Throttle duplicate notifications
196
+ * - Map events to priorities
197
+ *
198
+ * ## Dependencies
199
+ * - Notification channel implementations
200
+ * - Policy notification configuration
201
+ *
202
+ * ## Key Methods
203
+ * - `notify()` - send notification with priority routing
204
+ *
205
+ * ## Error Conditions
206
+ * - Channel send failures are logged but don't block
207
+ *
208
+ * @example
209
+ * ```typescript
210
+ * const notifier = new NotifierService(config, dashboardUrl);
211
+ * await notifier.notify('gate_failed', 'my_feature', 'Gate fast failed', { gate: 'fast' });
212
+ * ```
213
+ *
214
+ * ## Supported Channels
215
+ * - desktop: notify-send
216
+ * - slack: webhook
217
+ * - webhook: generic HTTP POST
218
+ */
162
219
  export class NotifierService {
163
220
  private readonly config: NotificationConfig;
164
221
  private readonly channels: Map<string, NotifierChannel>;
@@ -222,6 +279,19 @@ export class NotifierService {
222
279
  return false;
223
280
  }
224
281
 
282
+ /**
283
+ * Sends notification with priority-based routing.
284
+ *
285
+ * @param event - notification event type
286
+ * @param featureId - optional feature identifier
287
+ * @param message - notification message
288
+ * @param details - optional additional details
289
+ *
290
+ * @example
291
+ * ```typescript
292
+ * await notifier.notify('gate_failed', 'my_feature', 'Gate fast failed', { gate: 'fast' });
293
+ * ```
294
+ */
225
295
  async notify(
226
296
  event: NotificationEvent,
227
297
  context: { feature_id?: string; message: string; details?: Record<string, unknown> },
@@ -47,6 +47,10 @@ function normalizeFromWorktree(
47
47
  return path.relative(repoRoot, absolute).replaceAll('\\\\', '/');
48
48
  }
49
49
 
50
+ /**
51
+ * @fileoverview Patch validation and application service.
52
+ */
53
+
50
54
  export interface PatchServicePort {
51
55
  getRepoRoot(): string;
52
56
  getPolicySnapshot(): AnyRecord;
@@ -63,6 +67,41 @@ export interface PatchServicePort {
63
67
  ): Promise<AnyRecord>;
64
68
  }
65
69
 
70
+ /**
71
+ * Manages patch validation and atomic application.
72
+ *
73
+ * ## Responsibilities
74
+ * - Validate unified diff format
75
+ * - Enforce plan area restrictions
76
+ * - Apply policy path rules
77
+ * - Verify lock requirements
78
+ * - Apply patches atomically to worktree
79
+ *
80
+ * ## Dependencies
81
+ * Depends on {@link PatchServicePort} for:
82
+ * - Plan and policy access
83
+ * - State operations
84
+ * - Worktree path resolution
85
+ *
86
+ * ## Key Methods
87
+ * - `repoApplyPatch()` - validate and apply unified diff
88
+ * - `validatePatchPaths()` - enforce plan/policy path rules
89
+ * - `assertPlanLocksHeld()` - verify required locks
90
+ *
91
+ * ## Error Conditions
92
+ * - PATCH_VALIDATION_FAILED - invalid diff format or path violations
93
+ * - LOCK_NOT_HELD - required locks not acquired
94
+ * - PLAN_NOT_FOUND - no accepted plan exists
95
+ *
96
+ * @example
97
+ * ```typescript
98
+ * const patchService = new PatchService(port);
99
+ * await patchService.repoApplyPatch('my_feature', unifiedDiff);
100
+ * ```
101
+ *
102
+ * ## Thread Safety
103
+ * Patch application is atomic within feature worktree.
104
+ */
66
105
  export class PatchService {
67
106
  private readonly port: PatchServicePort;
68
107
  private readonly gateSelectionService: GateSelectionService;
@@ -72,6 +111,12 @@ export class PatchService {
72
111
  this.gateSelectionService = new GateSelectionService(port);
73
112
  }
74
113
 
114
+ /**
115
+ * Loads accepted plan for a feature.
116
+ *
117
+ * @param featureId - feature identifier
118
+ * @returns Plan object or null if not found
119
+ */
75
120
  async loadAcceptedPlan(featureId: string): Promise<AnyRecord | null> {
76
121
  const plan = await readJson(this.port.planPath(featureId), null);
77
122
  if (!plan && this.port.getPolicySnapshot().patch_policy.enforce_plan) {
@@ -102,6 +147,13 @@ export class PatchService {
102
147
  return sortResourcesDeterministically(resources);
103
148
  }
104
149
 
150
+ /**
151
+ * Verifies required resource locks are held for plan.
152
+ *
153
+ * @param featureId - feature identifier
154
+ * @param plan - plan requiring locks
155
+ * @throws LOCK_NOT_HELD - required locks not held
156
+ */
105
157
  async assertPlanLocksHeld(featureId: string, plan: AnyRecord): Promise<void> {
106
158
  const state = await this.port.readState(featureId);
107
159
  const held = new Set(readHeldLocks(state.frontMatter));
@@ -124,6 +176,24 @@ export class PatchService {
124
176
  }
125
177
  }
126
178
 
179
+ /**
180
+ * Validates patch paths against plan areas and policy rules.
181
+ *
182
+ * Enforces:
183
+ * - Paths must be in plan allowed_areas
184
+ * - Paths must not be in plan forbidden_areas
185
+ * - Paths must not violate policy path rules
186
+ *
187
+ * @param featureId - feature identifier
188
+ * @param patch - unified diff content
189
+ * @param plan - accepted plan with area restrictions
190
+ * @throws PATCH_VALIDATION_FAILED - path violations detected
191
+ *
192
+ * @example
193
+ * ```typescript
194
+ * await patchService.validatePatchPaths('my_feature', diff, plan);
195
+ * ```
196
+ */
127
197
  async validatePatchPaths(
128
198
  featureId: string,
129
199
  parsedDiff: ReturnType<typeof parseUnifiedDiff>,
@@ -199,6 +269,31 @@ export class PatchService {
199
269
  return normalizedTouched;
200
270
  }
201
271
 
272
+ /**
273
+ * Validates and applies unified diff to feature worktree.
274
+ *
275
+ * Full validation pipeline:
276
+ * 1. Load accepted plan
277
+ * 2. Verify required locks held
278
+ * 3. Validate patch format
279
+ * 4. Enforce path restrictions
280
+ * 5. Apply patch atomically
281
+ * 6. Update state with patch metadata
282
+ *
283
+ * @param featureId - feature identifier
284
+ * @param patch - unified diff content
285
+ * @returns Success response with applied patch metadata
286
+ * @throws PLAN_NOT_FOUND - no accepted plan
287
+ * @throws LOCK_NOT_HELD - required locks not held
288
+ * @throws PATCH_VALIDATION_FAILED - invalid format or path violations
289
+ * @throws PATCH_APPLICATION_FAILED - git apply failed
290
+ *
291
+ * @example
292
+ * ```typescript
293
+ * const diff = `--- a/file.ts\n+++ b/file.ts\n...`;
294
+ * await patchService.repoApplyPatch('my_feature', diff);
295
+ * ```
296
+ */
202
297
  async repoApplyPatch(
203
298
  featureId: string,
204
299
  unifiedDiff: string,