@bpmsoftwaresolutions/ai-engine-client 1.1.87 → 1.1.88

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.
@@ -1,11 +1,3420 @@
1
+ import { cleanText, isPlainObject } from '../utils/communication.js';
2
+
3
+ function cleanList(value) {
4
+ if (!Array.isArray(value)) return [];
5
+ return value.map((item) => cleanText(item)).filter(Boolean);
6
+ }
7
+
8
+ function looksLikeUuid(value) {
9
+ const text = cleanText(value);
10
+ return Boolean(text && /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(text));
11
+ }
12
+
13
+ function countRoadmapProjectionLines(markdown) {
14
+ const lines = [];
15
+ let inSummary = false;
16
+ for (const line of String(markdown || '').split(/\r?\n/)) {
17
+ if (line.startsWith('## Roadmap Summary')) {
18
+ inSummary = true;
19
+ continue;
20
+ }
21
+ if (inSummary && line.startsWith('## ')) {
22
+ break;
23
+ }
24
+ if (inSummary && line.startsWith('- ')) {
25
+ lines.push(line);
26
+ }
27
+ }
28
+ const wanted = [
29
+ 'Total Items',
30
+ 'Total Tasks',
31
+ 'Total Subtasks',
32
+ 'Total Acceptance Checks',
33
+ 'Open Acceptance Checks',
34
+ 'Completion Percentage',
35
+ ];
36
+ return lines.filter((line) => wanted.some((label) => line.startsWith(`- ${label}:`)));
37
+ }
38
+
1
39
  export function createWorkflowCompositionDomain(client) {
2
40
  return {
3
- registerModernizationAsset: (request) => client.registerModernizationAsset(request),
4
- classifyModernizationAsset: (request) => client.classifyModernizationAsset(request),
5
- discoverSalvageCandidates: (request) => client.discoverSalvageCandidates(request),
6
- createModernizationWorkPacket: (request) => client.createModernizationWorkPacket(request),
7
- requestModernizationWrapperExecution: (request) => client.requestModernizationWrapperExecution(request),
8
- getModernizationWrapperEvidence: (request) => client.getModernizationWrapperEvidence(request),
9
- decideModernizationGate: (request) => client.decideModernizationGate(request),
41
+ registerModernizationAsset: (request) => registerModernizationAsset(client, request),
42
+ classifyModernizationAsset: (request) => classifyModernizationAsset(client, request),
43
+ discoverSalvageCandidates: (request) => discoverSalvageCandidates(client, request),
44
+ createModernizationWorkPacket: (request) => createModernizationWorkPacket(client, request),
45
+ requestModernizationWrapperExecution: (request) => requestModernizationWrapperExecution(client, request),
46
+ getModernizationWrapperEvidence: (request) => getModernizationWrapperEvidence(client, request),
47
+ decideModernizationGate: (request) => decideModernizationGate(client, request),
48
+ };
49
+ }
50
+
51
+ export async function registerModernizationAsset(client, {
52
+ projectIdentifier,
53
+ projectId,
54
+ relatedProjectId,
55
+ related_project_id,
56
+ startWorkBody = {},
57
+ startWorkRequest = {},
58
+ resumeProjectWorkOptions = {},
59
+ asset = {},
60
+ modernizationAsset = {},
61
+ assetName,
62
+ asset_name,
63
+ assetType,
64
+ asset_type,
65
+ sourceRef,
66
+ source_ref,
67
+ originSystem,
68
+ origin_system,
69
+ businessContext,
70
+ business_context,
71
+ suspectedValue,
72
+ suspected_value,
73
+ knownRisks = [],
74
+ known_risks = [],
75
+ evidenceRefs = [],
76
+ evidence_refs = [],
77
+ handoffNotes,
78
+ handoff_notes,
79
+ assignedClassifier,
80
+ assigned_classifier,
81
+ classificationRequired,
82
+ classification_required,
83
+ submittedBy,
84
+ submitted_by,
85
+ includePortfolioBundle = true,
86
+ includeProjectRoadmap = true,
87
+ includeProjectActiveItem = true,
88
+ metadata = {},
89
+ } = {}) {
90
+ const missingSurfaces = [];
91
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
92
+ const normalizedAsset = isPlainObject(modernizationAsset)
93
+ ? modernizationAsset
94
+ : (isPlainObject(asset) ? asset : {});
95
+ const normalizedProjectReference = cleanText(projectIdentifier)
96
+ || cleanText(projectId)
97
+ || cleanText(relatedProjectId)
98
+ || cleanText(related_project_id)
99
+ || cleanText(normalizedAsset.related_project_id)
100
+ || cleanText(normalizedAsset.relatedProjectId);
101
+ const normalizedAssetName = cleanText(asset_name) || cleanText(assetName) || cleanText(normalizedAsset.asset_name) || cleanText(normalizedAsset.assetName);
102
+ const normalizedAssetType = cleanText(asset_type) || cleanText(assetType) || cleanText(normalizedAsset.asset_type) || cleanText(normalizedAsset.assetType) || 'unknown';
103
+ const normalizedSourceRef = cleanText(source_ref) || cleanText(sourceRef) || cleanText(normalizedAsset.source_ref) || cleanText(normalizedAsset.sourceRef) || normalizedAssetName;
104
+ if (!normalizedAssetName && !normalizedSourceRef) {
105
+ throw new Error('asset_name or source_ref is required.');
106
+ }
107
+ const normalizedOriginSystem = cleanText(origin_system) || cleanText(originSystem) || cleanText(normalizedAsset.origin_system) || cleanText(normalizedAsset.originSystem);
108
+ const normalizedBusinessContext = cleanText(business_context) || cleanText(businessContext) || cleanText(normalizedAsset.business_context) || cleanText(normalizedAsset.businessContext);
109
+ const normalizedSuspectedValue = cleanText(suspected_value) || cleanText(suspectedValue) || cleanText(normalizedAsset.suspected_value) || cleanText(normalizedAsset.suspectedValue);
110
+ const normalizedKnownRisks = Array.isArray(known_risks)
111
+ ? known_risks
112
+ : (Array.isArray(knownRisks) ? knownRisks : normalizedAsset.known_risks || normalizedAsset.knownRisks || []);
113
+ const normalizedEvidenceRefs = Array.isArray(evidence_refs)
114
+ ? evidence_refs
115
+ : (Array.isArray(evidenceRefs) ? evidenceRefs : normalizedAsset.evidence_refs || normalizedAsset.evidenceRefs || []);
116
+ const normalizedHandoffNotes = cleanText(handoff_notes) || cleanText(handoffNotes) || cleanText(normalizedAsset.handoff_notes) || cleanText(normalizedAsset.handoffNotes);
117
+ const normalizedAssignedClassifier = cleanText(assigned_classifier)
118
+ || cleanText(assignedClassifier)
119
+ || cleanText(normalizedAsset.assigned_classifier)
120
+ || cleanText(normalizedAsset.assignedClassifier);
121
+ const normalizedSubmittedBy = cleanText(submitted_by)
122
+ || cleanText(submittedBy)
123
+ || client.agentSessionId
124
+ || client.actorId
125
+ || null;
126
+ const normalizedClassificationRequired = classification_required ?? classificationRequired ?? true;
127
+
128
+ let continuation = null;
129
+ let startWorkResult = null;
130
+ if (normalizedProjectReference) {
131
+ if (typeof client.resumeProjectWork === 'function') {
132
+ continuation = await client.resumeProjectWork({
133
+ projectIdentifier: normalizedProjectReference,
134
+ projectId: normalizedProjectReference,
135
+ requireClaim: false,
136
+ ...resumeProjectWorkOptions,
137
+ });
138
+ } else {
139
+ missingSurfaces.push('resumeProjectWork');
140
+ }
141
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
142
+ if (typeof client.startWork === 'function') {
143
+ startWorkResult = await client.startWork({
144
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
145
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
146
+ });
147
+ } else {
148
+ missingSurfaces.push('startWork');
149
+ }
150
+ } else {
151
+ throw new Error('projectIdentifier is required.');
152
+ }
153
+
154
+ const projectPayload = isPlainObject(continuation?.project)
155
+ ? continuation.project
156
+ : isPlainObject(startWorkResult?.project)
157
+ ? startWorkResult.project
158
+ : isPlainObject(continuation?.summary)
159
+ ? continuation.summary
160
+ : {};
161
+ const resolvedProjectId = cleanText(projectPayload.project_id)
162
+ || cleanText(projectPayload.projectId)
163
+ || normalizedProjectReference;
164
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
165
+ || cleanText(projectPayload.workflowId)
166
+ || cleanText(continuation?.workflow_id)
167
+ || cleanText(startWorkResult?.workflow_id);
168
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
169
+ || cleanText(projectPayload.workflowRunId)
170
+ || cleanText(continuation?.workflow_run_id)
171
+ || cleanText(startWorkResult?.workflow_run_id)
172
+ || cleanText(startWorkResult?.workflowRunId);
173
+
174
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
175
+ ? await client.getPortfolioBundle().catch(() => null)
176
+ : null;
177
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
178
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
179
+ : null;
180
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
181
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
182
+ : null;
183
+
184
+ let assetIntakeRecord = null;
185
+ const assetIntakeSurface = typeof client.createModernizationAssetIntakeRecord === 'function'
186
+ ? client.createModernizationAssetIntakeRecord.bind(client)
187
+ : null;
188
+ if (!assetIntakeSurface) {
189
+ missingSurfaces.push('createModernizationAssetIntakeRecord');
190
+ } else {
191
+ assetIntakeRecord = await assetIntakeSurface({
192
+ projectId: resolvedProjectId,
193
+ workflowId: resolvedWorkflowId,
194
+ workflowRunId: resolvedWorkflowRunId,
195
+ assetName: normalizedAssetName,
196
+ assetType: normalizedAssetType,
197
+ sourceRef: normalizedSourceRef,
198
+ originSystem: normalizedOriginSystem,
199
+ businessContext: normalizedBusinessContext,
200
+ suspectedValue: normalizedSuspectedValue,
201
+ knownRisks: normalizedKnownRisks,
202
+ relatedProjectId: resolvedProjectId,
203
+ evidenceRefs: normalizedEvidenceRefs,
204
+ handoffNotes: normalizedHandoffNotes,
205
+ submittedBy: normalizedSubmittedBy,
206
+ metadata: {
207
+ ...normalizedMetadata,
208
+ source: 'registerModernizationAsset',
209
+ },
210
+ });
211
+ }
212
+
213
+ let intakeObservation = null;
214
+ const observationSurface = typeof client.submitModernizationAssetObservation === 'function'
215
+ ? client.submitModernizationAssetObservation.bind(client)
216
+ : null;
217
+ if (!observationSurface) {
218
+ missingSurfaces.push('submitModernizationAssetObservation');
219
+ } else {
220
+ intakeObservation = await observationSurface({
221
+ projectId: resolvedProjectId,
222
+ workflowId: resolvedWorkflowId,
223
+ workflowRunId: resolvedWorkflowRunId,
224
+ assetName: normalizedAssetName,
225
+ assetType: normalizedAssetType,
226
+ sourceRef: normalizedSourceRef,
227
+ submittedBy: normalizedSubmittedBy,
228
+ observationKind: 'asset_intake',
229
+ observationState: 'registered',
230
+ observationSummary: normalizedBusinessContext || normalizedHandoffNotes || normalizedAssetName || normalizedSourceRef,
231
+ evidenceRefs: normalizedEvidenceRefs,
232
+ metadata: {
233
+ ...normalizedMetadata,
234
+ source: 'registerModernizationAsset',
235
+ },
236
+ });
237
+ }
238
+
239
+ let transferResult = null;
240
+ let watchResult = null;
241
+ const classifierTransferNeeded = Boolean(normalizedClassificationRequired && normalizedAssignedClassifier);
242
+ if (classifierTransferNeeded) {
243
+ const transferSurface = typeof client.transferWorkPacket === 'function'
244
+ ? client.transferWorkPacket.bind(client)
245
+ : null;
246
+ if (!transferSurface) {
247
+ missingSurfaces.push('transferWorkPacket');
248
+ } else {
249
+ transferResult = await transferSurface({
250
+ workflowRunId: resolvedWorkflowRunId,
251
+ transferKind: 'upstream_remediation',
252
+ objective: `Classify modernization asset ${normalizedAssetName || normalizedSourceRef}`,
253
+ requestedOutcome: 'Review and classify the modernization asset intake.',
254
+ target: {
255
+ intent: 'upstream_remediation',
256
+ recipient_mode: 'agent_session',
257
+ preferred_agent_session_id: normalizedAssignedClassifier,
258
+ preferred_role_key: normalizedAssignedClassifier,
259
+ },
260
+ artifacts: normalizedSourceRef ? [normalizedSourceRef] : [],
261
+ issues: normalizedKnownRisks,
262
+ expected_evidence: normalizedEvidenceRefs,
263
+ preferred_modes: ['bundle', 'artifact_refs', 'inline_payload'],
264
+ capabilities: {},
265
+ sender_agent_session_id: normalizedSubmittedBy,
266
+ sender_actor_session_id: null,
267
+ message_kind: 'handoff',
268
+ subject: normalizedAssetName || normalizedSourceRef || 'Modernization asset intake',
269
+ body_markdown: normalizedHandoffNotes || normalizedBusinessContext || normalizedSuspectedValue,
270
+ metadata: {
271
+ ...normalizedMetadata,
272
+ source: 'registerModernizationAsset',
273
+ asset_name: normalizedAssetName,
274
+ asset_type: normalizedAssetType,
275
+ source_ref: normalizedSourceRef,
276
+ origin_system: normalizedOriginSystem,
277
+ },
278
+ });
279
+ }
280
+ }
281
+
282
+ const transferPayload = isPlainObject(transferResult) ? transferResult : {};
283
+ const transferPacketId = cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
284
+ || cleanText(transferPayload.work_transfer_packet_id)
285
+ || cleanText(transferPayload.transfer_packet_id)
286
+ || cleanText(transferPayload.packet_id)
287
+ || null;
288
+ const transferChannelId = cleanText(transferPayload.communication_transfer_channel?.transfer_channel_id)
289
+ || cleanText(transferPayload.communication_transfer_channel?.channel_id)
290
+ || cleanText(transferPayload.transfer_channel?.transfer_channel_id)
291
+ || cleanText(transferPayload.transfer_channel_id)
292
+ || cleanText(transferPayload.channel_id)
293
+ || null;
294
+
295
+ if (classifierTransferNeeded && transferChannelId && transferPacketId) {
296
+ const watchSurface = typeof client.startMessageWatch === 'function'
297
+ ? client.startMessageWatch.bind(client)
298
+ : null;
299
+ if (!watchSurface) {
300
+ missingSurfaces.push('startMessageWatch');
301
+ } else {
302
+ watchResult = await watchSurface({
303
+ transferChannelId,
304
+ workTransferPacketId: transferPacketId,
305
+ workflowRunId: resolvedWorkflowRunId,
306
+ watchingAgentRole: normalizedSubmittedBy,
307
+ expectedFromRole: normalizedAssignedClassifier,
308
+ expectedMessageKind: 'response',
309
+ watchType: 'expected_peer_message',
310
+ watchingAgentSessionId: normalizedSubmittedBy,
311
+ expectedPayload: {
312
+ source_ref: normalizedSourceRef,
313
+ asset_type: normalizedAssetType,
314
+ classification_required: Boolean(normalizedClassificationRequired),
315
+ },
316
+ currentStatus: 'watching',
317
+ operatorNudge: normalizedHandoffNotes || normalizedBusinessContext || normalizedSuspectedValue,
318
+ metadata: {
319
+ ...normalizedMetadata,
320
+ source: 'registerModernizationAsset',
321
+ },
322
+ });
323
+ }
324
+ }
325
+
326
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
327
+ const watchId = cleanText(watchPayload.message_watch_id)
328
+ || cleanText(watchPayload.watch_id)
329
+ || cleanText(watchPayload.message_watch?.message_watch_id)
330
+ || cleanText(watchPayload.message_watch?.watch_id)
331
+ || null;
332
+ const assetId = cleanText(assetIntakeRecord?.asset_id)
333
+ || cleanText(assetIntakeRecord?.assetId)
334
+ || cleanText(assetIntakeRecord?.intake_record_id)
335
+ || cleanText(assetIntakeRecord?.intakeRecordId)
336
+ || cleanText(assetIntakeRecord?.modernization_asset_id)
337
+ || cleanText(assetIntakeRecord?.modernizationAssetId)
338
+ || null;
339
+ const intakeRecordId = cleanText(assetIntakeRecord?.intake_record_id)
340
+ || cleanText(assetIntakeRecord?.intakeRecordId)
341
+ || cleanText(assetIntakeRecord?.asset_id)
342
+ || cleanText(assetIntakeRecord?.assetId)
343
+ || null;
344
+
345
+ return {
346
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
347
+ project_id: resolvedProjectId || null,
348
+ asset_id: assetId,
349
+ intake_record_id: intakeRecordId,
350
+ asset_type: normalizedAssetType,
351
+ source_ref: normalizedSourceRef,
352
+ submitted_by: normalizedSubmittedBy,
353
+ classification_required: Boolean(normalizedClassificationRequired),
354
+ assigned_classifier: normalizedAssignedClassifier || null,
355
+ transfer_packet_id: transferPacketId,
356
+ watch_id: watchId,
357
+ operator_projection_metadata: {
358
+ portfolio_bundle: portfolioBundle,
359
+ project_roadmap_summary: projectRoadmapSummary,
360
+ project_roadmap_active_item: projectActiveItem,
361
+ asset_intake_record: assetIntakeRecord,
362
+ intake_observation: intakeObservation,
363
+ transfer: transferPayload,
364
+ message_watch: watchPayload,
365
+ },
366
+ missing_surfaces: [...new Set(missingSurfaces)],
367
+ project: projectPayload,
368
+ transfer: transferPayload,
369
+ asset_intake_record: assetIntakeRecord,
370
+ intake_observation: intakeObservation,
371
+ message_watch: watchPayload,
372
+ };
373
+ }
374
+
375
+ export async function classifyModernizationAsset(client, {
376
+ projectIdentifier,
377
+ projectId,
378
+ relatedProjectId,
379
+ related_project_id,
380
+ startWorkBody = {},
381
+ startWorkRequest = {},
382
+ resumeProjectWorkOptions = {},
383
+ asset = {},
384
+ modernizationAsset = {},
385
+ classification = {},
386
+ modernizationClassification = {},
387
+ assetId,
388
+ asset_id,
389
+ intakeRecordId,
390
+ intake_record_id,
391
+ assetType,
392
+ asset_type,
393
+ sourceRef,
394
+ source_ref,
395
+ classificationCategory,
396
+ classification_category,
397
+ domainArea,
398
+ domain_area,
399
+ reusePotential,
400
+ reuse_potential,
401
+ modernizationNeed,
402
+ modernization_need,
403
+ knownRisks = [],
404
+ known_risks = [],
405
+ evidenceRefs = [],
406
+ evidence_refs = [],
407
+ recommendedNextStep,
408
+ recommended_next_step,
409
+ classificationConfidence,
410
+ classification_confidence,
411
+ reviewRequired,
412
+ review_required,
413
+ assignedReviewer,
414
+ assigned_reviewer,
415
+ handoffNotes,
416
+ handoff_notes,
417
+ submittedBy,
418
+ submitted_by,
419
+ includePortfolioBundle = true,
420
+ includeProjectRoadmap = true,
421
+ includeProjectActiveItem = true,
422
+ metadata = {},
423
+ } = {}) {
424
+ const missingSurfaces = [];
425
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
426
+ const normalizedAsset = isPlainObject(modernizationAsset)
427
+ ? modernizationAsset
428
+ : (isPlainObject(asset) ? asset : {});
429
+ const normalizedClassification = isPlainObject(modernizationClassification)
430
+ ? modernizationClassification
431
+ : (isPlainObject(classification) ? classification : {});
432
+ const normalizedProjectReference = cleanText(projectIdentifier)
433
+ || cleanText(projectId)
434
+ || cleanText(relatedProjectId)
435
+ || cleanText(related_project_id)
436
+ || cleanText(normalizedAsset.related_project_id)
437
+ || cleanText(normalizedAsset.relatedProjectId)
438
+ || cleanText(normalizedClassification.related_project_id)
439
+ || cleanText(normalizedClassification.relatedProjectId);
440
+ const normalizedAssetId = cleanText(asset_id)
441
+ || cleanText(assetId)
442
+ || cleanText(intake_record_id)
443
+ || cleanText(intakeRecordId)
444
+ || cleanText(normalizedAsset.asset_id)
445
+ || cleanText(normalizedAsset.assetId)
446
+ || cleanText(normalizedAsset.intake_record_id)
447
+ || cleanText(normalizedAsset.intakeRecordId);
448
+ const normalizedSourceRef = cleanText(source_ref)
449
+ || cleanText(sourceRef)
450
+ || cleanText(normalizedAsset.source_ref)
451
+ || cleanText(normalizedAsset.sourceRef)
452
+ || normalizedAssetId;
453
+ if (!normalizedAssetId && !normalizedSourceRef) {
454
+ throw new Error('asset_id, intake_record_id, or source_ref is required.');
455
+ }
456
+ const normalizedAssetType = cleanText(asset_type)
457
+ || cleanText(assetType)
458
+ || cleanText(normalizedAsset.asset_type)
459
+ || cleanText(normalizedAsset.assetType)
460
+ || 'unknown';
461
+ const normalizedClassificationCategory = cleanText(classification_category)
462
+ || cleanText(classificationCategory)
463
+ || cleanText(normalizedClassification.classification_category)
464
+ || cleanText(normalizedClassification.classificationCategory)
465
+ || 'uncategorized';
466
+ const normalizedDomainArea = cleanText(domain_area)
467
+ || cleanText(domainArea)
468
+ || cleanText(normalizedClassification.domain_area)
469
+ || cleanText(normalizedClassification.domainArea);
470
+ const normalizedReusePotential = cleanText(reuse_potential)
471
+ || cleanText(reusePotential)
472
+ || cleanText(normalizedClassification.reuse_potential)
473
+ || cleanText(normalizedClassification.reusePotential);
474
+ const normalizedModernizationNeed = cleanText(modernization_need)
475
+ || cleanText(modernizationNeed)
476
+ || cleanText(normalizedClassification.modernization_need)
477
+ || cleanText(normalizedClassification.modernizationNeed);
478
+ const normalizedRecommendedNextStep = cleanText(recommended_next_step)
479
+ || cleanText(recommendedNextStep)
480
+ || cleanText(normalizedClassification.recommended_next_step)
481
+ || cleanText(normalizedClassification.recommendedNextStep);
482
+ const normalizedClassificationConfidence = cleanText(classification_confidence)
483
+ || cleanText(classificationConfidence)
484
+ || cleanText(normalizedClassification.classification_confidence)
485
+ || cleanText(normalizedClassification.classificationConfidence);
486
+ const normalizedKnownRisks = Array.isArray(known_risks)
487
+ ? known_risks
488
+ : (Array.isArray(knownRisks) ? knownRisks : normalizedAsset.known_risks || normalizedAsset.knownRisks || []);
489
+ const normalizedEvidenceRefs = Array.isArray(evidence_refs)
490
+ ? evidence_refs
491
+ : (Array.isArray(evidenceRefs) ? evidenceRefs : normalizedAsset.evidence_refs || normalizedAsset.evidenceRefs || []);
492
+ const normalizedHandoffNotes = cleanText(handoff_notes)
493
+ || cleanText(handoffNotes)
494
+ || cleanText(normalizedClassification.handoff_notes)
495
+ || cleanText(normalizedClassification.handoffNotes)
496
+ || cleanText(normalizedAsset.handoff_notes)
497
+ || cleanText(normalizedAsset.handoffNotes);
498
+ const normalizedAssignedReviewer = cleanText(assigned_reviewer)
499
+ || cleanText(assignedReviewer)
500
+ || cleanText(normalizedClassification.assigned_reviewer)
501
+ || cleanText(normalizedClassification.assignedReviewer);
502
+ const normalizedSubmittedBy = cleanText(submitted_by)
503
+ || cleanText(submittedBy)
504
+ || client.agentSessionId
505
+ || client.actorId
506
+ || null;
507
+ const normalizedReviewRequired = review_required ?? reviewRequired ?? true;
508
+
509
+ let continuation = null;
510
+ let startWorkResult = null;
511
+ if (normalizedProjectReference) {
512
+ if (typeof client.resumeProjectWork === 'function') {
513
+ continuation = await client.resumeProjectWork({
514
+ projectIdentifier: normalizedProjectReference,
515
+ projectId: normalizedProjectReference,
516
+ requireClaim: false,
517
+ ...resumeProjectWorkOptions,
518
+ });
519
+ } else {
520
+ missingSurfaces.push('resumeProjectWork');
521
+ }
522
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
523
+ if (typeof client.startWork === 'function') {
524
+ startWorkResult = await client.startWork({
525
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
526
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
527
+ });
528
+ } else {
529
+ missingSurfaces.push('startWork');
530
+ }
531
+ }
532
+
533
+ const projectPayload = isPlainObject(continuation?.project)
534
+ ? continuation.project
535
+ : isPlainObject(startWorkResult?.project)
536
+ ? startWorkResult.project
537
+ : isPlainObject(continuation?.summary)
538
+ ? continuation.summary
539
+ : {};
540
+ const resolvedProjectId = cleanText(projectPayload.project_id)
541
+ || cleanText(projectPayload.projectId)
542
+ || normalizedProjectReference;
543
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
544
+ || cleanText(projectPayload.workflowId)
545
+ || cleanText(continuation?.workflow_id)
546
+ || cleanText(startWorkResult?.workflow_id);
547
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
548
+ || cleanText(projectPayload.workflowRunId)
549
+ || cleanText(continuation?.workflow_run_id)
550
+ || cleanText(startWorkResult?.workflow_run_id)
551
+ || cleanText(startWorkResult?.workflowRunId);
552
+
553
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
554
+ ? await client.getPortfolioBundle().catch(() => null)
555
+ : null;
556
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
557
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
558
+ : null;
559
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
560
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
561
+ : null;
562
+
563
+ let registeredAssetRecord = null;
564
+ const intakeLookupSurface = typeof client.getModernizationAssetIntakeRecord === 'function'
565
+ ? client.getModernizationAssetIntakeRecord.bind(client)
566
+ : null;
567
+ if (!intakeLookupSurface) {
568
+ missingSurfaces.push('getModernizationAssetIntakeRecord');
569
+ } else {
570
+ registeredAssetRecord = await intakeLookupSurface({
571
+ projectId: resolvedProjectId,
572
+ workflowId: resolvedWorkflowId,
573
+ workflowRunId: resolvedWorkflowRunId,
574
+ assetId: normalizedAssetId,
575
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
576
+ sourceRef: normalizedSourceRef,
577
+ metadata: {
578
+ ...normalizedMetadata,
579
+ source: 'classifyModernizationAsset',
580
+ },
581
+ });
582
+ }
583
+
584
+ let classificationRecord = null;
585
+ const classificationSurface = typeof client.createModernizationAssetClassificationRecord === 'function'
586
+ ? client.createModernizationAssetClassificationRecord.bind(client)
587
+ : null;
588
+ if (!classificationSurface) {
589
+ missingSurfaces.push('createModernizationAssetClassificationRecord');
590
+ } else {
591
+ classificationRecord = await classificationSurface({
592
+ projectId: resolvedProjectId,
593
+ workflowId: resolvedWorkflowId,
594
+ workflowRunId: resolvedWorkflowRunId,
595
+ assetId: normalizedAssetId,
596
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
597
+ assetType: normalizedAssetType,
598
+ sourceRef: normalizedSourceRef,
599
+ classificationCategory: normalizedClassificationCategory,
600
+ domainArea: normalizedDomainArea,
601
+ reusePotential: normalizedReusePotential,
602
+ modernizationNeed: normalizedModernizationNeed,
603
+ knownRisks: normalizedKnownRisks,
604
+ recommendedNextStep: normalizedRecommendedNextStep,
605
+ classificationConfidence: normalizedClassificationConfidence,
606
+ evidenceRefs: normalizedEvidenceRefs,
607
+ reviewRequired: Boolean(normalizedReviewRequired),
608
+ assignedReviewer: normalizedAssignedReviewer,
609
+ submittedBy: normalizedSubmittedBy,
610
+ handoffNotes: normalizedHandoffNotes,
611
+ metadata: {
612
+ ...normalizedMetadata,
613
+ source: 'classifyModernizationAsset',
614
+ },
615
+ });
616
+ }
617
+
618
+ let classificationObservation = null;
619
+ const observationSurface = typeof client.submitModernizationAssetClassificationObservation === 'function'
620
+ ? client.submitModernizationAssetClassificationObservation.bind(client)
621
+ : null;
622
+ if (!observationSurface) {
623
+ missingSurfaces.push('submitModernizationAssetClassificationObservation');
624
+ } else {
625
+ classificationObservation = await observationSurface({
626
+ projectId: resolvedProjectId,
627
+ workflowId: resolvedWorkflowId,
628
+ workflowRunId: resolvedWorkflowRunId,
629
+ assetId: normalizedAssetId,
630
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
631
+ assetType: normalizedAssetType,
632
+ sourceRef: normalizedSourceRef,
633
+ classificationCategory: normalizedClassificationCategory,
634
+ classificationConfidence: normalizedClassificationConfidence,
635
+ evidenceRefs: normalizedEvidenceRefs,
636
+ submittedBy: normalizedSubmittedBy,
637
+ observationKind: 'asset_classification',
638
+ observationState: 'prepared',
639
+ observationSummary: normalizedClassificationCategory || normalizedDomainArea || normalizedAssetType || normalizedSourceRef,
640
+ metadata: {
641
+ ...normalizedMetadata,
642
+ source: 'classifyModernizationAsset',
643
+ },
644
+ });
645
+ }
646
+
647
+ let transferResult = null;
648
+ let watchResult = null;
649
+ let heartbeatResult = null;
650
+ const reviewTransferNeeded = Boolean(normalizedReviewRequired && normalizedAssignedReviewer);
651
+ if (reviewTransferNeeded) {
652
+ const transferSurface = typeof client.transferWorkPacket === 'function'
653
+ ? client.transferWorkPacket.bind(client)
654
+ : null;
655
+ if (!transferSurface) {
656
+ missingSurfaces.push('transferWorkPacket');
657
+ } else {
658
+ transferResult = await transferSurface({
659
+ workflowRunId: resolvedWorkflowRunId,
660
+ transferKind: 'upstream_remediation',
661
+ objective: `Review modernization asset classification ${normalizedSourceRef || normalizedAssetId}`,
662
+ requestedOutcome: 'Review and enrich the modernization asset classification.',
663
+ target: {
664
+ intent: 'upstream_remediation',
665
+ recipient_mode: 'agent_session',
666
+ preferred_agent_session_id: normalizedAssignedReviewer,
667
+ preferred_role_key: normalizedAssignedReviewer,
668
+ },
669
+ artifacts: normalizedSourceRef ? [normalizedSourceRef] : [],
670
+ issues: normalizedKnownRisks,
671
+ expected_evidence: normalizedEvidenceRefs,
672
+ preferred_modes: ['bundle', 'artifact_refs', 'inline_payload'],
673
+ capabilities: {},
674
+ sender_agent_session_id: normalizedSubmittedBy,
675
+ sender_actor_session_id: null,
676
+ message_kind: 'handoff',
677
+ subject: normalizedClassificationCategory || normalizedSourceRef || 'Modernization asset classification',
678
+ body_markdown: normalizedHandoffNotes || normalizedRecommendedNextStep || normalizedClassificationCategory,
679
+ metadata: {
680
+ ...normalizedMetadata,
681
+ source: 'classifyModernizationAsset',
682
+ asset_id: normalizedAssetId,
683
+ intake_record_id: cleanText(intake_record_id) || cleanText(intakeRecordId),
684
+ asset_type: normalizedAssetType,
685
+ classification_category: normalizedClassificationCategory,
686
+ domain_area: normalizedDomainArea,
687
+ },
688
+ });
689
+ }
690
+ }
691
+
692
+ const transferPayload = isPlainObject(transferResult) ? transferResult : {};
693
+ const transferPacketId = cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
694
+ || cleanText(transferPayload.work_transfer_packet_id)
695
+ || cleanText(transferPayload.transfer_packet_id)
696
+ || cleanText(transferPayload.packet_id)
697
+ || null;
698
+ const transferChannelId = cleanText(transferPayload.communication_transfer_channel?.transfer_channel_id)
699
+ || cleanText(transferPayload.communication_transfer_channel?.channel_id)
700
+ || cleanText(transferPayload.transfer_channel?.transfer_channel_id)
701
+ || cleanText(transferPayload.transfer_channel_id)
702
+ || cleanText(transferPayload.channel_id)
703
+ || null;
704
+
705
+ if (reviewTransferNeeded && transferChannelId && transferPacketId) {
706
+ const watchSurface = typeof client.startMessageWatch === 'function'
707
+ ? client.startMessageWatch.bind(client)
708
+ : null;
709
+ if (!watchSurface) {
710
+ missingSurfaces.push('startMessageWatch');
711
+ } else {
712
+ watchResult = await watchSurface({
713
+ transferChannelId,
714
+ workTransferPacketId: transferPacketId,
715
+ workflowRunId: resolvedWorkflowRunId,
716
+ watchingAgentRole: normalizedSubmittedBy,
717
+ expectedFromRole: normalizedAssignedReviewer,
718
+ expectedMessageKind: 'response',
719
+ watchType: 'expected_peer_message',
720
+ watchingAgentSessionId: normalizedSubmittedBy,
721
+ expectedPayload: {
722
+ asset_id: normalizedAssetId,
723
+ classification_category: normalizedClassificationCategory,
724
+ review_required: Boolean(normalizedReviewRequired),
725
+ },
726
+ currentStatus: 'watching',
727
+ operatorNudge: normalizedHandoffNotes || normalizedRecommendedNextStep || normalizedClassificationCategory,
728
+ metadata: {
729
+ ...normalizedMetadata,
730
+ source: 'classifyModernizationAsset',
731
+ },
732
+ });
733
+ }
734
+ }
735
+
736
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
737
+ const watchId = cleanText(watchPayload.message_watch_id)
738
+ || cleanText(watchPayload.watch_id)
739
+ || cleanText(watchPayload.message_watch?.message_watch_id)
740
+ || cleanText(watchPayload.message_watch?.watch_id)
741
+ || null;
742
+
743
+ if ((classificationRecord || classificationObservation || transferResult) && typeof client.postCollaborationHeartbeat === 'function') {
744
+ try {
745
+ heartbeatResult = await client.postCollaborationHeartbeat({
746
+ transferChannelId: transferChannelId || undefined,
747
+ workTransferPacketId: transferPacketId || undefined,
748
+ workflowRunId: resolvedWorkflowRunId,
749
+ participantRole: normalizedReviewRequired && normalizedAssignedReviewer ? 'classifier' : 'warehouse',
750
+ currentPhase: reviewTransferNeeded ? 'review_pending' : 'classification_prepared',
751
+ currentTaskSummary: normalizedClassificationCategory || normalizedSourceRef || 'Modernization asset classification',
752
+ });
753
+ } catch (error) {
754
+ void error;
755
+ }
756
+ }
757
+
758
+ const heartbeatPayload = isPlainObject(heartbeatResult) ? heartbeatResult : {};
759
+ const classificationId = cleanText(classificationRecord?.classification_id)
760
+ || cleanText(classificationRecord?.classificationId)
761
+ || cleanText(classificationRecord?.intake_classification_id)
762
+ || cleanText(classificationRecord?.intakeClassificationId)
763
+ || null;
764
+ const assetRecordId = cleanText(registeredAssetRecord?.asset_id)
765
+ || cleanText(registeredAssetRecord?.assetId)
766
+ || cleanText(registeredAssetRecord?.intake_record_id)
767
+ || cleanText(registeredAssetRecord?.intakeRecordId)
768
+ || cleanText(normalizedAssetId)
769
+ || null;
770
+ const intakeRecordResolvedId = cleanText(registeredAssetRecord?.intake_record_id)
771
+ || cleanText(registeredAssetRecord?.intakeRecordId)
772
+ || cleanText(registeredAssetRecord?.asset_id)
773
+ || cleanText(registeredAssetRecord?.assetId)
774
+ || cleanText(intake_record_id)
775
+ || cleanText(intakeRecordId)
776
+ || null;
777
+
778
+ return {
779
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
780
+ project_id: resolvedProjectId || null,
781
+ asset_id: assetRecordId,
782
+ intake_record_id: intakeRecordResolvedId,
783
+ classification_id: classificationId,
784
+ asset_type: normalizedAssetType,
785
+ classification_category: normalizedClassificationCategory,
786
+ reuse_potential: normalizedReusePotential || null,
787
+ risk_level: normalizedClassification.risk_level || normalizedClassification.riskLevel || normalizedKnownRisks[0] || null,
788
+ classification_confidence: normalizedClassificationConfidence || null,
789
+ assigned_reviewer: normalizedAssignedReviewer || null,
790
+ source_ref: normalizedSourceRef,
791
+ submitted_by: normalizedSubmittedBy,
792
+ review_required: Boolean(normalizedReviewRequired),
793
+ transfer_packet_id: transferPacketId,
794
+ watch_id: watchId,
795
+ heartbeat_status: cleanText(heartbeatPayload.activity_state)
796
+ || cleanText(heartbeatPayload.collaboration_heartbeat?.activity_state)
797
+ || cleanText(heartbeatPayload.status)
798
+ || cleanText(heartbeatPayload.heartbeat_status)
799
+ || null,
800
+ operator_projection_metadata: {
801
+ portfolio_bundle: portfolioBundle,
802
+ project_roadmap_summary: projectRoadmapSummary,
803
+ project_roadmap_active_item: projectActiveItem,
804
+ registered_asset_record: registeredAssetRecord,
805
+ classification_record: classificationRecord,
806
+ classification_observation: classificationObservation,
807
+ review_transfer: transferPayload,
808
+ message_watch: watchPayload,
809
+ heartbeat: heartbeatPayload,
810
+ },
811
+ missing_surfaces: [...new Set(missingSurfaces)],
812
+ project: projectPayload,
813
+ registered_asset_record: registeredAssetRecord,
814
+ classification_record: classificationRecord,
815
+ classification_observation: classificationObservation,
816
+ transfer: transferPayload,
817
+ message_watch: watchPayload,
818
+ heartbeat: heartbeatPayload,
819
+ };
820
+ }
821
+
822
+ export async function discoverSalvageCandidates(client, {
823
+ projectIdentifier,
824
+ projectId,
825
+ relatedProjectId,
826
+ related_project_id,
827
+ startWorkBody = {},
828
+ startWorkRequest = {},
829
+ resumeProjectWorkOptions = {},
830
+ asset = {},
831
+ modernizationAsset = {},
832
+ classification = {},
833
+ modernizationClassification = {},
834
+ assetId,
835
+ asset_id,
836
+ intakeRecordId,
837
+ intake_record_id,
838
+ classificationId,
839
+ classification_id,
840
+ sourceRef,
841
+ source_ref,
842
+ assetType,
843
+ asset_type,
844
+ classificationCategory,
845
+ classification_category,
846
+ domainArea,
847
+ domain_area,
848
+ reusePotential,
849
+ reuse_potential,
850
+ modernizationNeed,
851
+ modernization_need,
852
+ riskLevel,
853
+ risk_level,
854
+ knownRisks = [],
855
+ known_risks = [],
856
+ evidenceRefs = [],
857
+ evidence_refs = [],
858
+ recommendedNextStep,
859
+ recommended_next_step,
860
+ reviewRequired,
861
+ review_required,
862
+ assignedReviewer,
863
+ assigned_reviewer,
864
+ candidateSearchIntent,
865
+ candidate_search_intent,
866
+ candidateSearchQuery,
867
+ candidate_search_query,
868
+ relatedSymbols = [],
869
+ related_symbols = [],
870
+ relatedQualifiedNames = [],
871
+ related_qualified_names = [],
872
+ relatedFilePaths = [],
873
+ related_file_paths = [],
874
+ maxCandidates = 10,
875
+ submittedBy,
876
+ submitted_by,
877
+ includePortfolioBundle = true,
878
+ includeProjectRoadmap = true,
879
+ includeProjectActiveItem = true,
880
+ metadata = {},
881
+ } = {}) {
882
+ const missingSurfaces = [];
883
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
884
+ const normalizedAsset = isPlainObject(modernizationAsset)
885
+ ? modernizationAsset
886
+ : (isPlainObject(asset) ? asset : {});
887
+ const normalizedClassification = isPlainObject(modernizationClassification)
888
+ ? modernizationClassification
889
+ : (isPlainObject(classification) ? classification : {});
890
+ const normalizedProjectReference = cleanText(projectIdentifier)
891
+ || cleanText(projectId)
892
+ || cleanText(relatedProjectId)
893
+ || cleanText(related_project_id)
894
+ || cleanText(normalizedAsset.related_project_id)
895
+ || cleanText(normalizedAsset.relatedProjectId)
896
+ || cleanText(normalizedClassification.related_project_id)
897
+ || cleanText(normalizedClassification.relatedProjectId);
898
+ const normalizedAssetId = cleanText(asset_id)
899
+ || cleanText(assetId)
900
+ || cleanText(intake_record_id)
901
+ || cleanText(intakeRecordId)
902
+ || cleanText(normalizedAsset.asset_id)
903
+ || cleanText(normalizedAsset.assetId)
904
+ || cleanText(normalizedAsset.intake_record_id)
905
+ || cleanText(normalizedAsset.intakeRecordId);
906
+ const normalizedClassificationId = cleanText(classification_id)
907
+ || cleanText(classificationId)
908
+ || cleanText(normalizedClassification.classification_id)
909
+ || cleanText(normalizedClassification.classificationId);
910
+ const normalizedSourceRef = cleanText(source_ref)
911
+ || cleanText(sourceRef)
912
+ || cleanText(normalizedAsset.source_ref)
913
+ || cleanText(normalizedAsset.sourceRef)
914
+ || normalizedAssetId;
915
+ if (!normalizedAssetId && !normalizedSourceRef && !normalizedClassificationId) {
916
+ throw new Error('asset_id, intake_record_id, classification_id, or source_ref is required.');
917
+ }
918
+ const normalizedAssetType = cleanText(asset_type)
919
+ || cleanText(assetType)
920
+ || cleanText(normalizedAsset.asset_type)
921
+ || cleanText(normalizedAsset.assetType)
922
+ || 'unknown';
923
+ const normalizedClassificationCategory = cleanText(classification_category)
924
+ || cleanText(classificationCategory)
925
+ || cleanText(normalizedClassification.classification_category)
926
+ || cleanText(normalizedClassification.classificationCategory)
927
+ || 'uncategorized';
928
+ const normalizedDomainArea = cleanText(domain_area)
929
+ || cleanText(domainArea)
930
+ || cleanText(normalizedClassification.domain_area)
931
+ || cleanText(normalizedClassification.domainArea);
932
+ const normalizedReusePotential = cleanText(reuse_potential)
933
+ || cleanText(reusePotential)
934
+ || cleanText(normalizedClassification.reuse_potential)
935
+ || cleanText(normalizedClassification.reusePotential);
936
+ const normalizedModernizationNeed = cleanText(modernization_need)
937
+ || cleanText(modernizationNeed)
938
+ || cleanText(normalizedClassification.modernization_need)
939
+ || cleanText(normalizedClassification.modernizationNeed);
940
+ const normalizedRiskLevel = cleanText(risk_level)
941
+ || cleanText(riskLevel)
942
+ || cleanText(normalizedClassification.risk_level)
943
+ || cleanText(normalizedClassification.riskLevel)
944
+ || null;
945
+ const normalizedRecommendedNextStep = cleanText(recommended_next_step)
946
+ || cleanText(recommendedNextStep)
947
+ || cleanText(normalizedClassification.recommended_next_step)
948
+ || cleanText(normalizedClassification.recommendedNextStep);
949
+ const normalizedKnownRisks = Array.isArray(known_risks)
950
+ ? known_risks
951
+ : (Array.isArray(knownRisks) ? knownRisks : normalizedAsset.known_risks || normalizedAsset.knownRisks || []);
952
+ const normalizedEvidenceRefs = Array.isArray(evidence_refs)
953
+ ? evidence_refs
954
+ : (Array.isArray(evidenceRefs) ? evidenceRefs : normalizedAsset.evidence_refs || normalizedAsset.evidenceRefs || []);
955
+ const normalizedAssignedReviewer = cleanText(assigned_reviewer)
956
+ || cleanText(assignedReviewer)
957
+ || cleanText(normalizedClassification.assigned_reviewer)
958
+ || cleanText(normalizedClassification.assignedReviewer);
959
+ const normalizedSubmittedBy = cleanText(submitted_by)
960
+ || cleanText(submittedBy)
961
+ || client.agentSessionId
962
+ || client.actorId
963
+ || null;
964
+ const normalizedReviewRequired = review_required ?? reviewRequired ?? true;
965
+ const normalizedCandidateSearchIntent = cleanText(candidate_search_intent)
966
+ || cleanText(candidateSearchIntent)
967
+ || normalizedClassificationCategory
968
+ || normalizedDomainArea
969
+ || normalizedSourceRef
970
+ || normalizedAssetType;
971
+ const normalizedCandidateSearchQuery = cleanText(candidate_search_query)
972
+ || cleanText(candidateSearchQuery)
973
+ || [
974
+ normalizedClassificationCategory,
975
+ normalizedDomainArea,
976
+ normalizedModernizationNeed,
977
+ normalizedSourceRef,
978
+ normalizedAssetType,
979
+ ].filter(Boolean).join(' ');
980
+ const normalizedRelatedSymbols = cleanList(related_symbols.length > 0 ? related_symbols : relatedSymbols);
981
+ const normalizedRelatedQualifiedNames = cleanList(related_qualified_names.length > 0 ? related_qualified_names : relatedQualifiedNames);
982
+ const normalizedRelatedFilePaths = cleanList(related_file_paths.length > 0 ? related_file_paths : relatedFilePaths);
983
+ const normalizedMaxCandidates = Number.isFinite(Number(maxCandidates)) && Number(maxCandidates) > 0
984
+ ? Number(maxCandidates)
985
+ : 10;
986
+
987
+ let continuation = null;
988
+ let startWorkResult = null;
989
+ if (normalizedProjectReference) {
990
+ if (typeof client.resumeProjectWork === 'function') {
991
+ continuation = await client.resumeProjectWork({
992
+ projectIdentifier: normalizedProjectReference,
993
+ projectId: normalizedProjectReference,
994
+ requireClaim: false,
995
+ ...resumeProjectWorkOptions,
996
+ });
997
+ } else {
998
+ missingSurfaces.push('resumeProjectWork');
999
+ }
1000
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
1001
+ if (typeof client.startWork === 'function') {
1002
+ startWorkResult = await client.startWork({
1003
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
1004
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
1005
+ });
1006
+ } else {
1007
+ missingSurfaces.push('startWork');
1008
+ }
1009
+ }
1010
+
1011
+ const projectPayload = isPlainObject(continuation?.project)
1012
+ ? continuation.project
1013
+ : isPlainObject(startWorkResult?.project)
1014
+ ? startWorkResult.project
1015
+ : isPlainObject(continuation?.summary)
1016
+ ? continuation.summary
1017
+ : {};
1018
+ const resolvedProjectId = cleanText(projectPayload.project_id)
1019
+ || cleanText(projectPayload.projectId)
1020
+ || normalizedProjectReference;
1021
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
1022
+ || cleanText(projectPayload.workflowId)
1023
+ || cleanText(continuation?.workflow_id)
1024
+ || cleanText(startWorkResult?.workflow_id);
1025
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
1026
+ || cleanText(projectPayload.workflowRunId)
1027
+ || cleanText(continuation?.workflow_run_id)
1028
+ || cleanText(startWorkResult?.workflow_run_id)
1029
+ || cleanText(startWorkResult?.workflowRunId);
1030
+
1031
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
1032
+ ? await client.getPortfolioBundle().catch(() => null)
1033
+ : null;
1034
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
1035
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
1036
+ : null;
1037
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
1038
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
1039
+ : null;
1040
+
1041
+ let assetIntakeRecord = null;
1042
+ const intakeLookupSurface = typeof client.getModernizationAssetIntakeRecord === 'function'
1043
+ ? client.getModernizationAssetIntakeRecord.bind(client)
1044
+ : null;
1045
+ if (!intakeLookupSurface) {
1046
+ missingSurfaces.push('getModernizationAssetIntakeRecord');
1047
+ } else {
1048
+ assetIntakeRecord = await intakeLookupSurface({
1049
+ projectId: resolvedProjectId,
1050
+ workflowId: resolvedWorkflowId,
1051
+ workflowRunId: resolvedWorkflowRunId,
1052
+ assetId: normalizedAssetId,
1053
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
1054
+ sourceRef: normalizedSourceRef,
1055
+ metadata: {
1056
+ ...normalizedMetadata,
1057
+ source: 'discoverSalvageCandidates',
1058
+ },
1059
+ });
1060
+ }
1061
+
1062
+ let classificationRecord = null;
1063
+ const classificationLookupSurface = typeof client.getModernizationAssetClassificationRecord === 'function'
1064
+ ? client.getModernizationAssetClassificationRecord.bind(client)
1065
+ : null;
1066
+ if (!classificationLookupSurface) {
1067
+ missingSurfaces.push('getModernizationAssetClassificationRecord');
1068
+ } else {
1069
+ classificationRecord = await classificationLookupSurface({
1070
+ projectId: resolvedProjectId,
1071
+ workflowId: resolvedWorkflowId,
1072
+ workflowRunId: resolvedWorkflowRunId,
1073
+ assetId: normalizedAssetId,
1074
+ classificationId: normalizedClassificationId,
1075
+ sourceRef: normalizedSourceRef,
1076
+ metadata: {
1077
+ ...normalizedMetadata,
1078
+ source: 'discoverSalvageCandidates',
1079
+ },
1080
+ });
1081
+ }
1082
+
1083
+ let codeIntentResult = null;
1084
+ if (typeof client.searchCodeByIntent === 'function') {
1085
+ codeIntentResult = await client.searchCodeByIntent({
1086
+ intentText: normalizedCandidateSearchIntent,
1087
+ repoKey: normalizedProjectReference || undefined,
1088
+ refName: normalizedSourceRef || undefined,
1089
+ maxCandidates: normalizedMaxCandidates,
1090
+ });
1091
+ } else {
1092
+ missingSurfaces.push('searchCodeByIntent');
1093
+ }
1094
+
1095
+ if (typeof client.getCodeContextForIntent === 'function') {
1096
+ await client.getCodeContextForIntent({
1097
+ intentText: normalizedCandidateSearchIntent,
1098
+ candidatePolicy: 'top_ranked',
1099
+ }).catch(() => null);
1100
+ } else {
1101
+ missingSurfaces.push('getCodeContextForIntent');
1102
+ }
1103
+
1104
+ let symbolSearchResult = null;
1105
+ if (typeof client.searchSymbols === 'function') {
1106
+ symbolSearchResult = await client.searchSymbols({
1107
+ query: normalizedCandidateSearchQuery,
1108
+ projectScope: resolvedProjectId || undefined,
1109
+ maxResults: normalizedMaxCandidates,
1110
+ }).catch(() => null);
1111
+ } else {
1112
+ missingSurfaces.push('searchSymbols');
1113
+ }
1114
+
1115
+ const relatedCodeResults = [];
1116
+ if (typeof client.getRelatedCode === 'function') {
1117
+ for (const qualifiedName of normalizedRelatedQualifiedNames) {
1118
+ relatedCodeResults.push(await client.getRelatedCode({
1119
+ qualifiedName,
1120
+ relationshipType: 'salvage_candidate',
1121
+ depth: 2,
1122
+ includeCode: false,
1123
+ requestedBy: normalizedSubmittedBy,
1124
+ }).catch(() => null));
1125
+ }
1126
+ for (const symbolKey of normalizedRelatedSymbols) {
1127
+ relatedCodeResults.push(await client.getRelatedCode({
1128
+ symbolKey,
1129
+ relationshipType: 'salvage_candidate',
1130
+ depth: 2,
1131
+ includeCode: false,
1132
+ requestedBy: normalizedSubmittedBy,
1133
+ }).catch(() => null));
1134
+ }
1135
+ } else if (normalizedRelatedSymbols.length > 0 || normalizedRelatedQualifiedNames.length > 0) {
1136
+ missingSurfaces.push('getRelatedCode');
1137
+ }
1138
+
1139
+ const toArray = (value) => {
1140
+ if (Array.isArray(value)) return value;
1141
+ if (isPlainObject(value)) {
1142
+ const candidates = value.candidates || value.results || value.items || value.symbols || value.related_code || value.relatedCode;
1143
+ if (Array.isArray(candidates)) return candidates;
1144
+ }
1145
+ return [];
1146
+ };
1147
+
1148
+ const mapCandidate = (entry, candidateType, fallbackRankReason) => {
1149
+ if (!isPlainObject(entry)) return null;
1150
+ const sourceRefValue = cleanText(entry.source_ref)
1151
+ || cleanText(entry.sourceRef)
1152
+ || cleanText(entry.qualified_name)
1153
+ || cleanText(entry.qualifiedName)
1154
+ || cleanText(entry.file_path)
1155
+ || cleanText(entry.filePath)
1156
+ || cleanText(entry.symbol_key)
1157
+ || cleanText(entry.symbolKey)
1158
+ || cleanText(entry.symbol_id)
1159
+ || cleanText(entry.symbolId)
1160
+ || null;
1161
+ const candidate = {
1162
+ candidate_type: cleanText(entry.candidate_type) || cleanText(entry.candidateType) || candidateType,
1163
+ source_ref: sourceRefValue,
1164
+ file_path: cleanText(entry.file_path) || cleanText(entry.filePath) || null,
1165
+ qualified_name: cleanText(entry.qualified_name) || cleanText(entry.qualifiedName) || null,
1166
+ responsibility_area: cleanText(entry.responsibility_area) || cleanText(entry.responsibilityArea) || normalizedDomainArea || normalizedClassificationCategory || null,
1167
+ reuse_potential: cleanText(entry.reuse_potential) || cleanText(entry.reusePotential) || normalizedReusePotential || null,
1168
+ modernization_need: cleanText(entry.modernization_need) || cleanText(entry.modernizationNeed) || normalizedModernizationNeed || null,
1169
+ risk_level: cleanText(entry.risk_level) || cleanText(entry.riskLevel) || normalizedRiskLevel || null,
1170
+ rank_reason: cleanText(entry.rank_reason) || cleanText(entry.rankReason) || fallbackRankReason,
1171
+ evidence_refs: Array.isArray(entry.evidence_refs) ? entry.evidence_refs : (Array.isArray(entry.evidenceRefs) ? entry.evidenceRefs : [...normalizedEvidenceRefs]),
1172
+ recommended_next_step: cleanText(entry.recommended_next_step) || cleanText(entry.recommendedNextStep) || normalizedRecommendedNextStep || null,
1173
+ };
1174
+ return candidate.source_ref || candidate.file_path || candidate.qualified_name ? candidate : null;
1175
+ };
1176
+
1177
+ const candidateMap = new Map();
1178
+ const addCandidates = (entries, candidateType, fallbackRankReason) => {
1179
+ for (const entry of entries) {
1180
+ const candidate = mapCandidate(entry, candidateType, fallbackRankReason);
1181
+ if (!candidate) continue;
1182
+ const key = candidate.source_ref || candidate.file_path || candidate.qualified_name;
1183
+ if (!candidateMap.has(key)) {
1184
+ candidateMap.set(key, candidate);
1185
+ }
1186
+ }
1187
+ };
1188
+
1189
+ addCandidates(toArray(codeIntentResult), 'intent_search_match', 'ranked by intent search');
1190
+ addCandidates(toArray(symbolSearchResult), 'symbol_search_match', 'ranked by inventory symbol search');
1191
+ for (const relatedCodeResult of relatedCodeResults) {
1192
+ addCandidates(toArray(relatedCodeResult), 'related_code_match', 'related code lookup');
1193
+ }
1194
+
1195
+ const candidates = [...candidateMap.values()].slice(0, normalizedMaxCandidates);
1196
+ const candidateCount = candidates.length;
1197
+
1198
+ let discoveryObservation = null;
1199
+ const discoveryObservationSurface = typeof client.submitModernizationSalvageDiscoveryObservation === 'function'
1200
+ ? client.submitModernizationSalvageDiscoveryObservation.bind(client)
1201
+ : null;
1202
+ if (!discoveryObservationSurface) {
1203
+ missingSurfaces.push('submitModernizationSalvageDiscoveryObservation');
1204
+ } else {
1205
+ discoveryObservation = await discoveryObservationSurface({
1206
+ projectId: resolvedProjectId,
1207
+ workflowId: resolvedWorkflowId,
1208
+ workflowRunId: resolvedWorkflowRunId,
1209
+ assetId: normalizedAssetId,
1210
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
1211
+ classificationId: normalizedClassificationId,
1212
+ candidateCount,
1213
+ candidates,
1214
+ evidenceRefs: normalizedEvidenceRefs,
1215
+ observationKind: 'salvage_candidate_discovery',
1216
+ observationState: 'prepared',
1217
+ observationSummary: normalizedCandidateSearchIntent || normalizedClassificationCategory || normalizedSourceRef || 'salvage candidate discovery',
1218
+ metadata: {
1219
+ ...normalizedMetadata,
1220
+ source: 'discoverSalvageCandidates',
1221
+ },
1222
+ });
1223
+ }
1224
+
1225
+ let transferResult = null;
1226
+ let watchResult = null;
1227
+ let heartbeatResult = null;
1228
+ const reviewTransferNeeded = Boolean(normalizedReviewRequired && normalizedAssignedReviewer);
1229
+ if (reviewTransferNeeded) {
1230
+ const transferSurface = typeof client.transferWorkPacket === 'function'
1231
+ ? client.transferWorkPacket.bind(client)
1232
+ : null;
1233
+ if (!transferSurface) {
1234
+ missingSurfaces.push('transferWorkPacket');
1235
+ } else {
1236
+ transferResult = await transferSurface({
1237
+ workflowRunId: resolvedWorkflowRunId,
1238
+ transferKind: 'upstream_remediation',
1239
+ objective: `Review salvage candidates for ${normalizedSourceRef || normalizedAssetId}`,
1240
+ requestedOutcome: 'Review and rank salvage candidates from governed inventory.',
1241
+ target: {
1242
+ intent: 'upstream_remediation',
1243
+ recipient_mode: 'agent_session',
1244
+ preferred_agent_session_id: normalizedAssignedReviewer,
1245
+ preferred_role_key: normalizedAssignedReviewer,
1246
+ },
1247
+ artifacts: normalizedSourceRef ? [normalizedSourceRef] : [],
1248
+ issues: normalizedKnownRisks,
1249
+ expected_evidence: normalizedEvidenceRefs,
1250
+ preferred_modes: ['bundle', 'artifact_refs', 'inline_payload'],
1251
+ capabilities: {},
1252
+ sender_agent_session_id: normalizedSubmittedBy,
1253
+ sender_actor_session_id: null,
1254
+ message_kind: 'handoff',
1255
+ subject: normalizedCandidateSearchIntent || normalizedSourceRef || 'Salvage candidate discovery',
1256
+ body_markdown: normalizedRecommendedNextStep || normalizedClassificationCategory || normalizedSourceRef,
1257
+ metadata: {
1258
+ ...normalizedMetadata,
1259
+ source: 'discoverSalvageCandidates',
1260
+ asset_id: normalizedAssetId,
1261
+ classification_id: normalizedClassificationId,
1262
+ classification_category: normalizedClassificationCategory,
1263
+ domain_area: normalizedDomainArea,
1264
+ },
1265
+ });
1266
+ }
1267
+ }
1268
+
1269
+ const transferPayload = isPlainObject(transferResult) ? transferResult : {};
1270
+ const transferPacketId = cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
1271
+ || cleanText(transferPayload.work_transfer_packet_id)
1272
+ || cleanText(transferPayload.transfer_packet_id)
1273
+ || cleanText(transferPayload.packet_id)
1274
+ || null;
1275
+ const transferChannelId = cleanText(transferPayload.communication_transfer_channel?.transfer_channel_id)
1276
+ || cleanText(transferPayload.communication_transfer_channel?.channel_id)
1277
+ || cleanText(transferPayload.transfer_channel?.transfer_channel_id)
1278
+ || cleanText(transferPayload.transfer_channel_id)
1279
+ || cleanText(transferPayload.channel_id)
1280
+ || null;
1281
+
1282
+ if (reviewTransferNeeded && transferChannelId && transferPacketId) {
1283
+ const watchSurface = typeof client.startMessageWatch === 'function'
1284
+ ? client.startMessageWatch.bind(client)
1285
+ : null;
1286
+ if (!watchSurface) {
1287
+ missingSurfaces.push('startMessageWatch');
1288
+ } else {
1289
+ watchResult = await watchSurface({
1290
+ transferChannelId,
1291
+ workTransferPacketId: transferPacketId,
1292
+ workflowRunId: resolvedWorkflowRunId,
1293
+ watchingAgentRole: normalizedSubmittedBy,
1294
+ expectedFromRole: normalizedAssignedReviewer,
1295
+ expectedMessageKind: 'response',
1296
+ watchType: 'expected_peer_message',
1297
+ watchingAgentSessionId: normalizedSubmittedBy,
1298
+ expectedPayload: {
1299
+ asset_id: normalizedAssetId,
1300
+ classification_id: normalizedClassificationId,
1301
+ candidate_count: candidateCount,
1302
+ },
1303
+ currentStatus: 'watching',
1304
+ operatorNudge: normalizedRecommendedNextStep || normalizedClassificationCategory || normalizedSourceRef,
1305
+ metadata: {
1306
+ ...normalizedMetadata,
1307
+ source: 'discoverSalvageCandidates',
1308
+ },
1309
+ });
1310
+ }
1311
+ }
1312
+
1313
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
1314
+ const watchId = cleanText(watchPayload.message_watch_id)
1315
+ || cleanText(watchPayload.watch_id)
1316
+ || cleanText(watchPayload.message_watch?.message_watch_id)
1317
+ || cleanText(watchPayload.message_watch?.watch_id)
1318
+ || null;
1319
+
1320
+ if ((discoveryObservation || transferResult) && typeof client.postCollaborationHeartbeat === 'function') {
1321
+ try {
1322
+ heartbeatResult = await client.postCollaborationHeartbeat({
1323
+ transferChannelId: transferChannelId || undefined,
1324
+ workTransferPacketId: transferPacketId || undefined,
1325
+ workflowRunId: resolvedWorkflowRunId,
1326
+ participantRole: reviewTransferNeeded ? 'salvage_reviewer' : 'salvage_discovery',
1327
+ currentPhase: reviewTransferNeeded ? 'review_pending' : 'discovery_complete',
1328
+ currentTaskSummary: normalizedCandidateSearchIntent || normalizedSourceRef || 'Salvage candidate discovery',
1329
+ });
1330
+ } catch (error) {
1331
+ void error;
1332
+ }
1333
+ }
1334
+
1335
+ const heartbeatPayload = isPlainObject(heartbeatResult) ? heartbeatResult : {};
1336
+ const heartbeatStatus = cleanText(heartbeatPayload.activity_state)
1337
+ || cleanText(heartbeatPayload.collaboration_heartbeat?.activity_state)
1338
+ || cleanText(heartbeatPayload.status)
1339
+ || cleanText(heartbeatPayload.heartbeat_status)
1340
+ || null;
1341
+
1342
+ return {
1343
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
1344
+ project_id: resolvedProjectId || null,
1345
+ asset_id: cleanText(assetIntakeRecord?.asset_id)
1346
+ || cleanText(assetIntakeRecord?.assetId)
1347
+ || normalizedAssetId
1348
+ || null,
1349
+ intake_record_id: cleanText(assetIntakeRecord?.intake_record_id)
1350
+ || cleanText(assetIntakeRecord?.intakeRecordId)
1351
+ || cleanText(intake_record_id)
1352
+ || cleanText(intakeRecordId)
1353
+ || null,
1354
+ classification_id: cleanText(classificationRecord?.classification_id)
1355
+ || cleanText(classificationRecord?.classificationId)
1356
+ || normalizedClassificationId
1357
+ || null,
1358
+ candidate_count: candidateCount,
1359
+ candidates,
1360
+ review_required: Boolean(normalizedReviewRequired),
1361
+ assigned_reviewer: normalizedAssignedReviewer || null,
1362
+ transfer_packet_id: transferPacketId,
1363
+ watch_id: watchId,
1364
+ heartbeat_status: heartbeatStatus,
1365
+ operator_projection_metadata: {
1366
+ portfolio_bundle: portfolioBundle,
1367
+ project_roadmap_summary: projectRoadmapSummary,
1368
+ project_roadmap_active_item: projectActiveItem,
1369
+ asset_intake_record: assetIntakeRecord,
1370
+ classification_record: classificationRecord,
1371
+ code_intent_search: codeIntentResult,
1372
+ symbol_search: symbolSearchResult,
1373
+ related_code: relatedCodeResults,
1374
+ discovery_observation: discoveryObservation,
1375
+ transfer: transferPayload,
1376
+ message_watch: watchPayload,
1377
+ heartbeat: heartbeatPayload,
1378
+ },
1379
+ missing_surfaces: [...new Set(missingSurfaces)],
1380
+ project: projectPayload,
1381
+ asset_intake_record: assetIntakeRecord,
1382
+ classification_record: classificationRecord,
1383
+ code_intent_search: codeIntentResult,
1384
+ symbol_search: symbolSearchResult,
1385
+ related_code: relatedCodeResults,
1386
+ discovery_observation: discoveryObservation,
1387
+ transfer: transferPayload,
1388
+ message_watch: watchPayload,
1389
+ heartbeat: heartbeatPayload,
1390
+ };
1391
+ }
1392
+
1393
+ export async function createModernizationWorkPacket(client, {
1394
+ projectIdentifier,
1395
+ projectId,
1396
+ relatedProjectId,
1397
+ related_project_id,
1398
+ startWorkBody = {},
1399
+ startWorkRequest = {},
1400
+ resumeProjectWorkOptions = {},
1401
+ asset = {},
1402
+ modernizationAsset = {},
1403
+ classification = {},
1404
+ modernizationClassification = {},
1405
+ assetId,
1406
+ asset_id,
1407
+ intakeRecordId,
1408
+ intake_record_id,
1409
+ classificationId,
1410
+ classification_id,
1411
+ selectedCandidates = [],
1412
+ selected_candidates = [],
1413
+ candidateIds = [],
1414
+ candidate_ids = [],
1415
+ candidateObjects = [],
1416
+ candidate_objects = [],
1417
+ sourceRef,
1418
+ source_ref,
1419
+ packetTitle,
1420
+ packet_title,
1421
+ problemStatement,
1422
+ problem_statement,
1423
+ recommendedModernization,
1424
+ recommended_modernization,
1425
+ affectedFilesOrSymbols = [],
1426
+ affected_files_or_symbols = [],
1427
+ acceptanceCriteria = [],
1428
+ acceptance_criteria = [],
1429
+ riskLevel,
1430
+ risk_level,
1431
+ evidenceRefs = [],
1432
+ evidence_refs = [],
1433
+ wrapperExecutionRequired,
1434
+ wrapper_execution_required,
1435
+ handoffNotes,
1436
+ handoff_notes,
1437
+ targetAgent,
1438
+ target_agent,
1439
+ assignedOwner,
1440
+ assigned_owner,
1441
+ collaborationRequired,
1442
+ collaboration_required,
1443
+ channelId,
1444
+ channel_id,
1445
+ transferChannelId,
1446
+ transfer_channel_id,
1447
+ submittedBy,
1448
+ submitted_by,
1449
+ includePortfolioBundle = true,
1450
+ includeProjectRoadmap = true,
1451
+ includeProjectActiveItem = true,
1452
+ includeTransferChannelProjection = true,
1453
+ metadata = {},
1454
+ } = {}) {
1455
+ const missingSurfaces = [];
1456
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
1457
+ const normalizedAsset = isPlainObject(modernizationAsset)
1458
+ ? modernizationAsset
1459
+ : (isPlainObject(asset) ? asset : {});
1460
+ const normalizedClassification = isPlainObject(modernizationClassification)
1461
+ ? modernizationClassification
1462
+ : (isPlainObject(classification) ? classification : {});
1463
+ const normalizedProjectReference = cleanText(projectIdentifier)
1464
+ || cleanText(projectId)
1465
+ || cleanText(relatedProjectId)
1466
+ || cleanText(related_project_id)
1467
+ || cleanText(normalizedAsset.related_project_id)
1468
+ || cleanText(normalizedAsset.relatedProjectId)
1469
+ || cleanText(normalizedClassification.related_project_id)
1470
+ || cleanText(normalizedClassification.relatedProjectId);
1471
+ const normalizedAssetId = cleanText(asset_id)
1472
+ || cleanText(assetId)
1473
+ || cleanText(intake_record_id)
1474
+ || cleanText(intakeRecordId)
1475
+ || cleanText(normalizedAsset.asset_id)
1476
+ || cleanText(normalizedAsset.assetId)
1477
+ || cleanText(normalizedAsset.intake_record_id)
1478
+ || cleanText(normalizedAsset.intakeRecordId);
1479
+ const normalizedClassificationId = cleanText(classification_id)
1480
+ || cleanText(classificationId)
1481
+ || cleanText(normalizedClassification.classification_id)
1482
+ || cleanText(normalizedClassification.classificationId);
1483
+ const normalizedSourceRef = cleanText(source_ref)
1484
+ || cleanText(sourceRef)
1485
+ || cleanText(normalizedAsset.source_ref)
1486
+ || cleanText(normalizedAsset.sourceRef)
1487
+ || normalizedAssetId;
1488
+ const normalizedPacketTitle = cleanText(packet_title) || cleanText(packetTitle);
1489
+ const normalizedProblemStatement = cleanText(problem_statement)
1490
+ || cleanText(problemStatement)
1491
+ || normalizedPacketTitle
1492
+ || normalizedSourceRef
1493
+ || 'Modernization work packet';
1494
+ const normalizedRecommendedModernization = cleanText(recommended_modernization)
1495
+ || cleanText(recommendedModernization)
1496
+ || cleanText(normalizedClassification.recommended_modernization)
1497
+ || cleanText(normalizedClassification.recommendedModernization);
1498
+ const normalizedRiskLevel = cleanText(risk_level)
1499
+ || cleanText(riskLevel)
1500
+ || cleanText(normalizedClassification.risk_level)
1501
+ || cleanText(normalizedClassification.riskLevel)
1502
+ || null;
1503
+ const normalizedHandoffNotes = cleanText(handoff_notes) || cleanText(handoffNotes);
1504
+ const normalizedSubmittedBy = cleanText(submitted_by)
1505
+ || cleanText(submittedBy)
1506
+ || client.agentSessionId
1507
+ || client.actorId
1508
+ || null;
1509
+ const normalizedTargetAgent = cleanText(target_agent) || cleanText(targetAgent) || cleanText(assigned_owner) || cleanText(assignedOwner) || null;
1510
+ const normalizedWrapperExecutionRequired = wrapper_execution_required ?? wrapperExecutionRequired ?? true;
1511
+ const normalizedCollaborationRequired = collaboration_required ?? collaborationRequired ?? Boolean(normalizedTargetAgent);
1512
+ const normalizedAffectedFilesOrSymbols = cleanList(affected_files_or_symbols.length > 0 ? affected_files_or_symbols : affectedFilesOrSymbols);
1513
+ const normalizedAcceptanceCriteria = cleanList(acceptance_criteria.length > 0 ? acceptance_criteria : acceptanceCriteria);
1514
+ const normalizedEvidenceRefs = cleanList(evidence_refs.length > 0 ? evidence_refs : evidenceRefs);
1515
+
1516
+ const candidateEntries = [
1517
+ ...(Array.isArray(selected_candidates) && selected_candidates.length > 0 ? selected_candidates : selectedCandidates),
1518
+ ...(Array.isArray(candidate_objects) && candidate_objects.length > 0 ? candidate_objects : candidateObjects),
1519
+ ];
1520
+ const normalizedCandidateIds = [];
1521
+ const normalizedCandidateRecords = [];
1522
+ for (const entry of candidateEntries) {
1523
+ if (typeof entry === 'string') {
1524
+ const candidateId = cleanText(entry);
1525
+ if (candidateId) normalizedCandidateIds.push(candidateId);
1526
+ continue;
1527
+ }
1528
+ if (!isPlainObject(entry)) continue;
1529
+ const candidateId = cleanText(entry.candidate_id)
1530
+ || cleanText(entry.candidateId)
1531
+ || cleanText(entry.salvage_candidate_id)
1532
+ || cleanText(entry.salvageCandidateId)
1533
+ || cleanText(entry.work_packet_candidate_id)
1534
+ || cleanText(entry.workPacketCandidateId)
1535
+ || cleanText(entry.source_ref)
1536
+ || cleanText(entry.sourceRef)
1537
+ || cleanText(entry.qualified_name)
1538
+ || cleanText(entry.qualifiedName);
1539
+ if (candidateId) normalizedCandidateIds.push(candidateId);
1540
+ normalizedCandidateRecords.push(entry);
1541
+ }
1542
+ for (const candidateId of Array.isArray(candidate_ids) && candidate_ids.length > 0 ? candidate_ids : candidateIds) {
1543
+ const normalizedCandidateId = cleanText(candidateId);
1544
+ if (normalizedCandidateId) normalizedCandidateIds.push(normalizedCandidateId);
1545
+ }
1546
+ const uniqueCandidateIds = [...new Set(normalizedCandidateIds)].filter(Boolean);
1547
+ if (uniqueCandidateIds.length === 0) {
1548
+ throw new Error('candidate_ids or selected_candidates is required.');
1549
+ }
1550
+
1551
+ let continuation = null;
1552
+ let startWorkResult = null;
1553
+ if (normalizedProjectReference) {
1554
+ if (typeof client.resumeProjectWork === 'function') {
1555
+ continuation = await client.resumeProjectWork({
1556
+ projectIdentifier: normalizedProjectReference,
1557
+ projectId: normalizedProjectReference,
1558
+ requireClaim: false,
1559
+ ...resumeProjectWorkOptions,
1560
+ });
1561
+ } else {
1562
+ missingSurfaces.push('resumeProjectWork');
1563
+ }
1564
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
1565
+ if (typeof client.startWork === 'function') {
1566
+ startWorkResult = await client.startWork({
1567
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
1568
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
1569
+ });
1570
+ } else {
1571
+ missingSurfaces.push('startWork');
1572
+ }
1573
+ }
1574
+
1575
+ const projectPayload = isPlainObject(continuation?.project)
1576
+ ? continuation.project
1577
+ : isPlainObject(startWorkResult?.project)
1578
+ ? startWorkResult.project
1579
+ : isPlainObject(continuation?.summary)
1580
+ ? continuation.summary
1581
+ : {};
1582
+ const resolvedProjectId = cleanText(projectPayload.project_id)
1583
+ || cleanText(projectPayload.projectId)
1584
+ || normalizedProjectReference;
1585
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
1586
+ || cleanText(projectPayload.workflowId)
1587
+ || cleanText(continuation?.workflow_id)
1588
+ || cleanText(startWorkResult?.workflow_id);
1589
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
1590
+ || cleanText(projectPayload.workflowRunId)
1591
+ || cleanText(continuation?.workflow_run_id)
1592
+ || cleanText(startWorkResult?.workflow_run_id)
1593
+ || cleanText(startWorkResult?.workflowRunId);
1594
+
1595
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
1596
+ ? await client.getPortfolioBundle().catch(() => null)
1597
+ : null;
1598
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
1599
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
1600
+ : null;
1601
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
1602
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
1603
+ : null;
1604
+
1605
+ let assetIntakeRecord = null;
1606
+ const intakeLookupSurface = typeof client.getModernizationAssetIntakeRecord === 'function'
1607
+ ? client.getModernizationAssetIntakeRecord.bind(client)
1608
+ : null;
1609
+ if (!intakeLookupSurface) {
1610
+ missingSurfaces.push('getModernizationAssetIntakeRecord');
1611
+ } else {
1612
+ assetIntakeRecord = await intakeLookupSurface({
1613
+ projectId: resolvedProjectId,
1614
+ workflowId: resolvedWorkflowId,
1615
+ workflowRunId: resolvedWorkflowRunId,
1616
+ assetId: normalizedAssetId,
1617
+ intakeRecordId: cleanText(intake_record_id) || cleanText(intakeRecordId),
1618
+ sourceRef: normalizedSourceRef,
1619
+ metadata: {
1620
+ ...normalizedMetadata,
1621
+ source: 'createModernizationWorkPacket',
1622
+ },
1623
+ });
1624
+ }
1625
+
1626
+ let classificationRecord = null;
1627
+ const classificationLookupSurface = typeof client.getModernizationAssetClassificationRecord === 'function'
1628
+ ? client.getModernizationAssetClassificationRecord.bind(client)
1629
+ : null;
1630
+ if (!classificationLookupSurface) {
1631
+ missingSurfaces.push('getModernizationAssetClassificationRecord');
1632
+ } else {
1633
+ classificationRecord = await classificationLookupSurface({
1634
+ projectId: resolvedProjectId,
1635
+ workflowId: resolvedWorkflowId,
1636
+ workflowRunId: resolvedWorkflowRunId,
1637
+ assetId: normalizedAssetId,
1638
+ classificationId: normalizedClassificationId,
1639
+ sourceRef: normalizedSourceRef,
1640
+ metadata: {
1641
+ ...normalizedMetadata,
1642
+ source: 'createModernizationWorkPacket',
1643
+ },
1644
+ });
1645
+ }
1646
+
1647
+ let candidateRecords = [];
1648
+ const candidateLookupSurface = typeof client.getModernizationSalvageCandidateRecord === 'function'
1649
+ ? client.getModernizationSalvageCandidateRecord.bind(client)
1650
+ : typeof client.getModernizationWorkPacketCandidateRecord === 'function'
1651
+ ? client.getModernizationWorkPacketCandidateRecord.bind(client)
1652
+ : null;
1653
+ if (!candidateLookupSurface) {
1654
+ missingSurfaces.push('getModernizationSalvageCandidateRecord');
1655
+ missingSurfaces.push('getModernizationWorkPacketCandidateRecord');
1656
+ } else {
1657
+ candidateRecords = await Promise.all(uniqueCandidateIds.map(async (candidateId) => {
1658
+ try {
1659
+ return await candidateLookupSurface({
1660
+ projectId: resolvedProjectId,
1661
+ workflowId: resolvedWorkflowId,
1662
+ workflowRunId: resolvedWorkflowRunId,
1663
+ candidateId,
1664
+ sourceRef: normalizedSourceRef,
1665
+ metadata: {
1666
+ ...normalizedMetadata,
1667
+ source: 'createModernizationWorkPacket',
1668
+ },
1669
+ });
1670
+ } catch (error) {
1671
+ void error;
1672
+ return null;
1673
+ }
1674
+ }));
1675
+ }
1676
+
1677
+ let packetRecord = null;
1678
+ const packetCreationSurface = typeof client.createModernizationWorkPacketRecord === 'function'
1679
+ ? client.createModernizationWorkPacketRecord.bind(client)
1680
+ : null;
1681
+ if (!packetCreationSurface) {
1682
+ missingSurfaces.push('createModernizationWorkPacketRecord');
1683
+ } else {
1684
+ packetRecord = await packetCreationSurface({
1685
+ projectId: resolvedProjectId,
1686
+ workflowId: resolvedWorkflowId,
1687
+ workflowRunId: resolvedWorkflowRunId,
1688
+ assetId: normalizedAssetId,
1689
+ classificationId: normalizedClassificationId,
1690
+ candidateIds: uniqueCandidateIds,
1691
+ packetTitle: normalizedPacketTitle || normalizedProblemStatement,
1692
+ sourceRef: normalizedSourceRef,
1693
+ problemStatement: normalizedProblemStatement,
1694
+ recommendedModernization: normalizedRecommendedModernization,
1695
+ affectedFilesOrSymbols: normalizedAffectedFilesOrSymbols,
1696
+ acceptanceCriteria: normalizedAcceptanceCriteria,
1697
+ riskLevel: normalizedRiskLevel,
1698
+ evidenceRefs: normalizedEvidenceRefs,
1699
+ wrapperExecutionRequired: Boolean(normalizedWrapperExecutionRequired),
1700
+ handoffNotes: normalizedHandoffNotes,
1701
+ metadata: {
1702
+ ...normalizedMetadata,
1703
+ source: 'createModernizationWorkPacket',
1704
+ },
1705
+ });
1706
+ }
1707
+
1708
+ const transferSurface = typeof client.transferWorkPacket === 'function'
1709
+ ? client.transferWorkPacket.bind(client)
1710
+ : null;
1711
+ if (!transferSurface) missingSurfaces.push('transferWorkPacket');
1712
+ const transferResult = transferSurface
1713
+ ? await transferSurface({
1714
+ workflowRunId: resolvedWorkflowRunId,
1715
+ transferKind: 'upstream_remediation',
1716
+ objective: normalizedProblemStatement || normalizedRecommendedModernization || 'Modernization work packet',
1717
+ requestedOutcome: normalizedRecommendedModernization || normalizedProblemStatement || 'Prepare modernization handoff.',
1718
+ target: normalizedTargetAgent
1719
+ ? {
1720
+ intent: 'upstream_remediation',
1721
+ recipient_mode: 'agent_session',
1722
+ preferred_agent_session_id: normalizedTargetAgent,
1723
+ preferred_role_key: normalizedTargetAgent,
1724
+ }
1725
+ : {
1726
+ intent: 'upstream_remediation',
1727
+ recipient_mode: 'role',
1728
+ preferred_role_key: 'modernization_execution',
1729
+ },
1730
+ artifacts: normalizedAffectedFilesOrSymbols,
1731
+ issues: [],
1732
+ expectedEvidence: normalizedAcceptanceCriteria,
1733
+ preferredModes: ['bundle', 'artifact_refs', 'inline_payload'],
1734
+ capabilities: {
1735
+ wrapper_execution_required: Boolean(normalizedWrapperExecutionRequired),
1736
+ selected_candidate_count: uniqueCandidateIds.length,
1737
+ },
1738
+ senderAgentSessionId: normalizedSubmittedBy,
1739
+ senderActorSessionId: null,
1740
+ messageKind: 'handoff',
1741
+ subject: normalizedPacketTitle || normalizedProblemStatement || 'Modernization work packet',
1742
+ bodyMarkdown: normalizedHandoffNotes || normalizedRecommendedModernization || normalizedProblemStatement,
1743
+ metadata: {
1744
+ ...normalizedMetadata,
1745
+ source: 'createModernizationWorkPacket',
1746
+ asset_id: normalizedAssetId,
1747
+ classification_id: normalizedClassificationId,
1748
+ source_ref: normalizedSourceRef,
1749
+ candidate_ids: uniqueCandidateIds,
1750
+ selected_candidates: normalizedCandidateRecords,
1751
+ wrapper_execution_required: Boolean(normalizedWrapperExecutionRequired),
1752
+ },
1753
+ })
1754
+ : null;
1755
+
1756
+ const transferPayload = isPlainObject(transferResult) ? transferResult : {};
1757
+ let transferPacketId = cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
1758
+ || cleanText(transferPayload.work_transfer_packet_id)
1759
+ || cleanText(transferPayload.transfer_packet_id)
1760
+ || cleanText(transferPayload.packet_id)
1761
+ || null;
1762
+
1763
+ const transferChannelInputId = cleanText(transfer_channel_id)
1764
+ || cleanText(transferChannelId)
1765
+ || cleanText(channel_id)
1766
+ || cleanText(channelId);
1767
+ const transferChannelSurface = transferChannelInputId
1768
+ ? (typeof client.resumeTransferChannel === 'function'
1769
+ ? client.resumeTransferChannel.bind(client)
1770
+ : null)
1771
+ : (transferPacketId && typeof client.openTransferChannel === 'function'
1772
+ ? client.openTransferChannel.bind(client)
1773
+ : null);
1774
+ if (!transferChannelSurface && (transferChannelInputId || transferPacketId)) {
1775
+ missingSurfaces.push(transferChannelInputId ? 'resumeTransferChannel' : 'openTransferChannel');
1776
+ }
1777
+ const channelResult = transferChannelSurface && transferPacketId
1778
+ ? await transferChannelSurface({
1779
+ transferChannelId: transferChannelInputId || undefined,
1780
+ workTransferPacketId: transferPacketId,
1781
+ workflowRunId: resolvedWorkflowRunId,
1782
+ channelKind: 'bidirectional',
1783
+ upstreamAgentSessionId: normalizedSubmittedBy,
1784
+ downstreamAgentSessionId: normalizedTargetAgent || undefined,
1785
+ evidenceRequiredForClosure: true,
1786
+ metadata: {
1787
+ ...normalizedMetadata,
1788
+ source: 'createModernizationWorkPacket',
1789
+ },
1790
+ })
1791
+ : null;
1792
+ const channelPayload = isPlainObject(channelResult) ? channelResult : {};
1793
+ const resolvedChannelId = cleanText(channelPayload.transfer_channel_id)
1794
+ || cleanText(channelPayload.channel_id)
1795
+ || cleanText(channelPayload.transfer_channel?.transfer_channel_id)
1796
+ || cleanText(channelPayload.communication_transfer_channel?.transfer_channel_id)
1797
+ || transferChannelInputId
1798
+ || null;
1799
+
1800
+ const ownershipSurface = normalizedTargetAgent && resolvedChannelId && typeof client.assignCollaborationOwnership === 'function'
1801
+ ? client.assignCollaborationOwnership.bind(client)
1802
+ : null;
1803
+ if (normalizedTargetAgent && !ownershipSurface) missingSurfaces.push('assignCollaborationOwnership');
1804
+ const ownershipResult = ownershipSurface
1805
+ ? await ownershipSurface({
1806
+ transferChannelId: resolvedChannelId,
1807
+ workTransferPacketId: transferPacketId,
1808
+ workflowRunId: resolvedWorkflowRunId,
1809
+ participantRole: 'modernization_owner',
1810
+ ownerAgentSessionId: normalizedTargetAgent,
1811
+ ownerActorSessionId: null,
1812
+ ownerLabel: normalizedTargetAgent,
1813
+ assignmentState: 'assigned',
1814
+ assignmentReason: normalizedProblemStatement || normalizedRecommendedModernization,
1815
+ currentPhase: 'modernization_work_packet',
1816
+ assignedByAgentSessionId: normalizedSubmittedBy,
1817
+ assignedByActorSessionId: null,
1818
+ metadata: {
1819
+ ...normalizedMetadata,
1820
+ source: 'createModernizationWorkPacket',
1821
+ },
1822
+ })
1823
+ : null;
1824
+ const ownershipPayload = isPlainObject(ownershipResult) ? ownershipResult : {};
1825
+
1826
+ const proposalSurface = resolvedChannelId && typeof client.postCollaborationProposal === 'function'
1827
+ ? client.postCollaborationProposal.bind(client)
1828
+ : null;
1829
+ if (resolvedChannelId && !proposalSurface) missingSurfaces.push('postCollaborationProposal');
1830
+ const proposalResult = proposalSurface
1831
+ ? await proposalSurface({
1832
+ transferChannelId: resolvedChannelId,
1833
+ workTransferPacketId: transferPacketId,
1834
+ workflowRunId: resolvedWorkflowRunId,
1835
+ proposalKind: 'modernization_work_packet',
1836
+ proposalState: 'proposed',
1837
+ participantRole: normalizedTargetAgent ? 'modernization_owner' : 'modernization_planner',
1838
+ proposalSummary: normalizedProblemStatement || normalizedRecommendedModernization || 'Modernization work packet',
1839
+ currentPhase: 'modernization_work_packet',
1840
+ expectedNextUpdate: normalizedAcceptanceCriteria.join('; ') || normalizedRecommendedModernization || normalizedProblemStatement,
1841
+ requiredEvidence: normalizedAcceptanceCriteria,
1842
+ responseSchema: {
1843
+ source_ref: normalizedSourceRef,
1844
+ risk_level: normalizedRiskLevel,
1845
+ candidate_ids: uniqueCandidateIds,
1846
+ wrapper_execution_required: Boolean(normalizedWrapperExecutionRequired),
1847
+ },
1848
+ blockerSummary: normalizedProblemStatement || normalizedRecommendedModernization,
1849
+ revisionNumber: 1,
1850
+ proposerAgentSessionId: normalizedSubmittedBy,
1851
+ proposerActorSessionId: null,
1852
+ metadata: {
1853
+ ...normalizedMetadata,
1854
+ source: 'createModernizationWorkPacket',
1855
+ },
1856
+ })
1857
+ : null;
1858
+ const proposalPayload = isPlainObject(proposalResult) ? proposalResult : {};
1859
+
1860
+ const watchSurface = resolvedChannelId && typeof client.startMessageWatch === 'function'
1861
+ ? client.startMessageWatch.bind(client)
1862
+ : null;
1863
+ if (resolvedChannelId && !watchSurface) missingSurfaces.push('startMessageWatch');
1864
+ const watchResult = watchSurface
1865
+ ? await watchSurface({
1866
+ transferChannelId: resolvedChannelId,
1867
+ workTransferPacketId: transferPacketId,
1868
+ workflowRunId: resolvedWorkflowRunId,
1869
+ watchingAgentRole: normalizedSubmittedBy,
1870
+ expectedFromRole: normalizedTargetAgent || 'modernization_owner',
1871
+ expectedMessageKind: 'response',
1872
+ watchType: 'expected_peer_message',
1873
+ watchingAgentSessionId: normalizedSubmittedBy,
1874
+ expectedPayload: {
1875
+ source_ref: normalizedSourceRef,
1876
+ candidate_ids: uniqueCandidateIds,
1877
+ expected_acknowledgement: 'modernization work packet received',
1878
+ },
1879
+ currentStatus: 'watching',
1880
+ operatorNudge: normalizedHandoffNotes || normalizedRecommendedModernization || normalizedProblemStatement,
1881
+ metadata: {
1882
+ ...normalizedMetadata,
1883
+ source: 'createModernizationWorkPacket',
1884
+ },
1885
+ })
1886
+ : null;
1887
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
1888
+
1889
+ const heartbeatSurface = resolvedChannelId && typeof client.postCollaborationHeartbeat === 'function'
1890
+ ? client.postCollaborationHeartbeat.bind(client)
1891
+ : null;
1892
+ if (resolvedChannelId && !heartbeatSurface) missingSurfaces.push('postCollaborationHeartbeat');
1893
+ const heartbeatResult = heartbeatSurface
1894
+ ? await heartbeatSurface({
1895
+ transferChannelId: resolvedChannelId,
1896
+ workTransferPacketId: transferPacketId,
1897
+ workflowRunId: resolvedWorkflowRunId,
1898
+ participantRole: normalizedTargetAgent ? 'modernization_owner' : 'modernization_planner',
1899
+ currentPhase: 'modernization_work_packet',
1900
+ currentTaskSummary: normalizedProblemStatement || normalizedRecommendedModernization || 'Modernization work packet',
1901
+ metadata: {
1902
+ ...normalizedMetadata,
1903
+ source: 'createModernizationWorkPacket',
1904
+ },
1905
+ }).catch(() => null)
1906
+ : null;
1907
+ const heartbeatPayload = isPlainObject(heartbeatResult) ? heartbeatResult : {};
1908
+
1909
+ const transferChannelProjectionSurface = includeTransferChannelProjection && resolvedChannelId
1910
+ ? (typeof client.getTransferChannelProjection === 'function'
1911
+ ? client.getTransferChannelProjection.bind(client)
1912
+ : typeof client.getLogaTransferChannelThreadProjection === 'function'
1913
+ ? client.getLogaTransferChannelThreadProjection.bind(client)
1914
+ : null)
1915
+ : null;
1916
+ if (includeTransferChannelProjection && resolvedChannelId && !transferChannelProjectionSurface) missingSurfaces.push('getTransferChannelProjection');
1917
+ const transferChannelProjection = transferChannelProjectionSurface && resolvedChannelId
1918
+ ? await transferChannelProjectionSurface(resolvedChannelId).catch(() => null)
1919
+ : null;
1920
+
1921
+ const modernizationPacketId = cleanText(packetRecord?.modernization_packet_id)
1922
+ || cleanText(packetRecord?.modernizationPacketId)
1923
+ || cleanText(packetRecord?.work_packet_id)
1924
+ || cleanText(packetRecord?.workPacketId)
1925
+ || null;
1926
+ const candidateCount = uniqueCandidateIds.length;
1927
+ const proposalId = cleanText(proposalPayload.collaboration_proposal_id)
1928
+ || cleanText(proposalPayload.proposal_id)
1929
+ || cleanText(proposalPayload.collaboration_proposal?.collaboration_proposal_id)
1930
+ || cleanText(proposalPayload.collaboration_proposal?.proposal_id)
1931
+ || null;
1932
+ const watchId = cleanText(watchPayload.message_watch_id)
1933
+ || cleanText(watchPayload.watch_id)
1934
+ || cleanText(watchPayload.message_watch?.message_watch_id)
1935
+ || cleanText(watchPayload.message_watch?.watch_id)
1936
+ || null;
1937
+ const expectedAcknowledgement = cleanText(watchPayload.expected_message_kind)
1938
+ || cleanText(watchPayload.message_watch?.expected_message_kind)
1939
+ || cleanText(watchPayload.message_watch?.expected_acknowledgement)
1940
+ || (normalizedTargetAgent ? 'acknowledgement' : null);
1941
+ const assignedOwnerResolved = cleanText(ownershipPayload.owner_agent_session_id)
1942
+ || cleanText(ownershipPayload.ownerAgentSessionId)
1943
+ || normalizedTargetAgent
1944
+ || null;
1945
+ const heartbeatStatus = cleanText(heartbeatPayload.collaboration_heartbeat?.activity_state)
1946
+ || cleanText(heartbeatPayload.activity_state)
1947
+ || cleanText(heartbeatPayload.status)
1948
+ || cleanText(heartbeatPayload.collaboration_heartbeat?.status)
1949
+ || null;
1950
+ const transferPacketResolvedId = transferPacketId
1951
+ || cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
1952
+ || cleanText(transferPayload.work_transfer_packet_id)
1953
+ || cleanText(transferPayload.transfer_packet_id)
1954
+ || cleanText(transferPayload.packet_id)
1955
+ || null;
1956
+
1957
+ return {
1958
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
1959
+ project_id: resolvedProjectId || null,
1960
+ asset_id: cleanText(assetIntakeRecord?.asset_id)
1961
+ || cleanText(assetIntakeRecord?.assetId)
1962
+ || normalizedAssetId
1963
+ || null,
1964
+ intake_record_id: cleanText(assetIntakeRecord?.intake_record_id)
1965
+ || cleanText(assetIntakeRecord?.intakeRecordId)
1966
+ || cleanText(intake_record_id)
1967
+ || cleanText(intakeRecordId)
1968
+ || null,
1969
+ classification_id: cleanText(classificationRecord?.classification_id)
1970
+ || cleanText(classificationRecord?.classificationId)
1971
+ || normalizedClassificationId
1972
+ || null,
1973
+ candidate_ids: uniqueCandidateIds,
1974
+ candidate_count: candidateCount,
1975
+ modernization_packet_id: modernizationPacketId,
1976
+ transfer_packet_id: transferPacketResolvedId,
1977
+ channel_id: resolvedChannelId,
1978
+ proposal_id: proposalId,
1979
+ assigned_owner: assignedOwnerResolved,
1980
+ watch_id: watchId,
1981
+ expected_acknowledgement: expectedAcknowledgement,
1982
+ heartbeat_status: heartbeatStatus,
1983
+ operator_projection_metadata: {
1984
+ portfolio_bundle: portfolioBundle,
1985
+ project_roadmap_summary: projectRoadmapSummary,
1986
+ project_roadmap_active_item: projectActiveItem,
1987
+ asset_intake_record: assetIntakeRecord,
1988
+ classification_record: classificationRecord,
1989
+ candidate_records: candidateRecords,
1990
+ modernization_packet_record: packetRecord,
1991
+ transfer: transferPayload,
1992
+ channel: channelPayload,
1993
+ ownership_assignment: ownershipPayload,
1994
+ proposal: proposalPayload,
1995
+ message_watch: watchPayload,
1996
+ heartbeat: heartbeatPayload,
1997
+ transfer_channel_projection: transferChannelProjection,
1998
+ },
1999
+ missing_surfaces: [...new Set(missingSurfaces)],
2000
+ project: projectPayload,
2001
+ asset_intake_record: assetIntakeRecord,
2002
+ classification_record: classificationRecord,
2003
+ candidate_records: candidateRecords,
2004
+ modernization_packet_record: packetRecord,
2005
+ transfer: transferPayload,
2006
+ channel: channelPayload,
2007
+ ownership_assignment: ownershipPayload,
2008
+ proposal: proposalPayload,
2009
+ message_watch: watchPayload,
2010
+ heartbeat: heartbeatPayload,
2011
+ selected_candidates: normalizedCandidateRecords,
2012
+ };
2013
+ }
2014
+
2015
+ export async function requestModernizationWrapperExecution(client, {
2016
+ projectIdentifier,
2017
+ projectId,
2018
+ relatedProjectId,
2019
+ related_project_id,
2020
+ startWorkBody = {},
2021
+ startWorkRequest = {},
2022
+ resumeProjectWorkOptions = {},
2023
+ modernizationPacket = {},
2024
+ modernization_packet = {},
2025
+ modernizationPacketId,
2026
+ modernization_packet_id,
2027
+ packetId,
2028
+ packet_id,
2029
+ sourceRef,
2030
+ source_ref,
2031
+ wrapperName,
2032
+ wrapper_name,
2033
+ wrapperContractRef,
2034
+ wrapper_contract_ref,
2035
+ executionScope = [],
2036
+ execution_scope = [],
2037
+ allowedBlastRadius = [],
2038
+ allowed_blast_radius = [],
2039
+ requiredEvidence = [],
2040
+ required_evidence = [],
2041
+ acceptanceCriteria = [],
2042
+ acceptance_criteria = [],
2043
+ riskLevel,
2044
+ risk_level,
2045
+ targetAgent,
2046
+ target_agent,
2047
+ handoffNotes,
2048
+ handoff_notes,
2049
+ collaborationRequired,
2050
+ collaboration_required,
2051
+ channelId,
2052
+ channel_id,
2053
+ transferChannelId,
2054
+ transfer_channel_id,
2055
+ assignedOwner,
2056
+ assigned_owner,
2057
+ wrapperExecutionRequired,
2058
+ wrapper_execution_required,
2059
+ submittedBy,
2060
+ submitted_by,
2061
+ includePortfolioBundle = true,
2062
+ includeProjectRoadmap = true,
2063
+ includeProjectActiveItem = true,
2064
+ includeTransferChannelProjection = true,
2065
+ metadata = {},
2066
+ } = {}) {
2067
+ const missingSurfaces = [];
2068
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
2069
+ const normalizedPacket = isPlainObject(modernization_packet)
2070
+ ? modernization_packet
2071
+ : (isPlainObject(modernizationPacket) ? modernizationPacket : {});
2072
+ const normalizedProjectReference = cleanText(projectIdentifier)
2073
+ || cleanText(projectId)
2074
+ || cleanText(relatedProjectId)
2075
+ || cleanText(related_project_id)
2076
+ || cleanText(normalizedPacket.project_id)
2077
+ || cleanText(normalizedPacket.projectId)
2078
+ || cleanText(normalizedPacket.related_project_id)
2079
+ || cleanText(normalizedPacket.relatedProjectId);
2080
+ const normalizedPacketId = cleanText(modernization_packet_id)
2081
+ || cleanText(modernizationPacketId)
2082
+ || cleanText(packet_id)
2083
+ || cleanText(packetId)
2084
+ || cleanText(normalizedPacket.modernization_packet_id)
2085
+ || cleanText(normalizedPacket.modernizationPacketId)
2086
+ || cleanText(normalizedPacket.packet_id)
2087
+ || cleanText(normalizedPacket.packetId);
2088
+ const normalizedSourceRef = cleanText(source_ref)
2089
+ || cleanText(sourceRef)
2090
+ || cleanText(normalizedPacket.source_ref)
2091
+ || cleanText(normalizedPacket.sourceRef)
2092
+ || normalizedPacketId;
2093
+ const normalizedWrapperName = cleanText(wrapper_name) || cleanText(wrapperName);
2094
+ const normalizedWrapperContractRef = cleanText(wrapper_contract_ref) || cleanText(wrapperContractRef);
2095
+ const normalizedExecutionScope = cleanList(execution_scope.length > 0 ? execution_scope : executionScope);
2096
+ const normalizedAllowedBlastRadius = cleanList(allowed_blast_radius.length > 0 ? allowed_blast_radius : allowedBlastRadius);
2097
+ const normalizedRequiredEvidence = cleanList(required_evidence.length > 0 ? required_evidence : requiredEvidence);
2098
+ const normalizedAcceptanceCriteria = cleanList(acceptance_criteria.length > 0 ? acceptance_criteria : acceptanceCriteria);
2099
+ const normalizedRiskLevel = cleanText(risk_level)
2100
+ || cleanText(riskLevel)
2101
+ || cleanText(normalizedPacket.risk_level)
2102
+ || cleanText(normalizedPacket.riskLevel)
2103
+ || null;
2104
+ const normalizedHandoffNotes = cleanText(handoff_notes) || cleanText(handoffNotes);
2105
+ const normalizedSubmittedBy = cleanText(submitted_by)
2106
+ || cleanText(submittedBy)
2107
+ || client.agentSessionId
2108
+ || client.actorId
2109
+ || null;
2110
+ const normalizedTargetAgent = cleanText(target_agent) || cleanText(targetAgent) || cleanText(assigned_owner) || cleanText(assignedOwner) || null;
2111
+ const normalizedWrapperExecutionRequired = wrapper_execution_required ?? wrapperExecutionRequired ?? true;
2112
+ const normalizedCollaborationRequired = collaboration_required ?? collaborationRequired ?? Boolean(normalizedTargetAgent || channelId || channel_id || transferChannelId || transfer_channel_id);
2113
+
2114
+ let continuation = null;
2115
+ let startWorkResult = null;
2116
+ if (normalizedProjectReference) {
2117
+ if (typeof client.resumeProjectWork === 'function') {
2118
+ continuation = await client.resumeProjectWork({
2119
+ projectIdentifier: normalizedProjectReference,
2120
+ projectId: normalizedProjectReference,
2121
+ requireClaim: false,
2122
+ ...resumeProjectWorkOptions,
2123
+ });
2124
+ } else {
2125
+ missingSurfaces.push('resumeProjectWork');
2126
+ }
2127
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
2128
+ if (typeof client.startWork === 'function') {
2129
+ startWorkResult = await client.startWork({
2130
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
2131
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
2132
+ });
2133
+ } else {
2134
+ missingSurfaces.push('startWork');
2135
+ }
2136
+ }
2137
+
2138
+ const projectPayload = isPlainObject(continuation?.project)
2139
+ ? continuation.project
2140
+ : isPlainObject(startWorkResult?.project)
2141
+ ? startWorkResult.project
2142
+ : isPlainObject(continuation?.summary)
2143
+ ? continuation.summary
2144
+ : {};
2145
+ const resolvedProjectId = cleanText(projectPayload.project_id)
2146
+ || cleanText(projectPayload.projectId)
2147
+ || normalizedProjectReference;
2148
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
2149
+ || cleanText(projectPayload.workflowId)
2150
+ || cleanText(continuation?.workflow_id)
2151
+ || cleanText(startWorkResult?.workflow_id);
2152
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
2153
+ || cleanText(projectPayload.workflowRunId)
2154
+ || cleanText(continuation?.workflow_run_id)
2155
+ || cleanText(startWorkResult?.workflow_run_id)
2156
+ || cleanText(startWorkResult?.workflowRunId);
2157
+
2158
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
2159
+ ? await client.getPortfolioBundle().catch(() => null)
2160
+ : null;
2161
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
2162
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
2163
+ : null;
2164
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
2165
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
2166
+ : null;
2167
+
2168
+ let packetRecord = null;
2169
+ const packetLookupSurface = typeof client.getModernizationWorkPacketRecord === 'function'
2170
+ ? client.getModernizationWorkPacketRecord.bind(client)
2171
+ : typeof client.getModernizationPacketRecord === 'function'
2172
+ ? client.getModernizationPacketRecord.bind(client)
2173
+ : null;
2174
+ if (!packetLookupSurface) {
2175
+ missingSurfaces.push('getModernizationWorkPacketRecord');
2176
+ missingSurfaces.push('getModernizationPacketRecord');
2177
+ } else {
2178
+ packetRecord = await packetLookupSurface({
2179
+ projectId: resolvedProjectId,
2180
+ workflowId: resolvedWorkflowId,
2181
+ workflowRunId: resolvedWorkflowRunId,
2182
+ modernizationPacketId: normalizedPacketId,
2183
+ packetId: normalizedPacketId,
2184
+ sourceRef: normalizedSourceRef,
2185
+ metadata: {
2186
+ ...normalizedMetadata,
2187
+ source: 'requestModernizationWrapperExecution',
2188
+ },
2189
+ }).catch(() => null);
2190
+ }
2191
+
2192
+ const packetRecordPayload = isPlainObject(packetRecord) ? packetRecord : {};
2193
+ const resolvedModernizationPacketId = cleanText(packetRecordPayload.modernization_packet_id)
2194
+ || cleanText(packetRecordPayload.modernizationPacketId)
2195
+ || cleanText(packetRecordPayload.work_packet_id)
2196
+ || cleanText(packetRecordPayload.workPacketId)
2197
+ || normalizedPacketId
2198
+ || null;
2199
+
2200
+ let wrapperRequestRecord = null;
2201
+ const wrapperRequestSurface = typeof client.createModernizationWrapperExecutionRequestRecord === 'function'
2202
+ ? client.createModernizationWrapperExecutionRequestRecord.bind(client)
2203
+ : typeof client.submitModernizationWrapperExecutionRequest === 'function'
2204
+ ? client.submitModernizationWrapperExecutionRequest.bind(client)
2205
+ : null;
2206
+ if (!wrapperRequestSurface) {
2207
+ missingSurfaces.push('createModernizationWrapperExecutionRequestRecord');
2208
+ missingSurfaces.push('submitModernizationWrapperExecutionRequest');
2209
+ } else {
2210
+ wrapperRequestRecord = await wrapperRequestSurface({
2211
+ projectId: resolvedProjectId,
2212
+ workflowId: resolvedWorkflowId,
2213
+ workflowRunId: resolvedWorkflowRunId,
2214
+ modernizationPacketId: resolvedModernizationPacketId,
2215
+ wrapperName: normalizedWrapperName,
2216
+ wrapperContractRef: normalizedWrapperContractRef,
2217
+ sourceRef: normalizedSourceRef,
2218
+ executionScope: normalizedExecutionScope,
2219
+ allowedBlastRadius: normalizedAllowedBlastRadius,
2220
+ requiredEvidence: normalizedRequiredEvidence,
2221
+ acceptanceCriteria: normalizedAcceptanceCriteria,
2222
+ riskLevel: normalizedRiskLevel,
2223
+ targetAgent: normalizedTargetAgent,
2224
+ handoffNotes: normalizedHandoffNotes,
2225
+ wrapperExecutionRequired: Boolean(normalizedWrapperExecutionRequired),
2226
+ metadata: {
2227
+ ...normalizedMetadata,
2228
+ source: 'requestModernizationWrapperExecution',
2229
+ },
2230
+ }).catch(() => null);
2231
+ }
2232
+
2233
+ let transferResult = null;
2234
+ const transferSurface = typeof client.transferWorkPacket === 'function'
2235
+ ? client.transferWorkPacket.bind(client)
2236
+ : null;
2237
+ if (!transferSurface) missingSurfaces.push('transferWorkPacket');
2238
+ if (transferSurface && (!wrapperRequestRecord || !wrapperRequestRecord.wrapper_execution_request_id) && (normalizedWrapperExecutionRequired || normalizedTargetAgent || normalizedCollaborationRequired)) {
2239
+ transferResult = await transferSurface({
2240
+ workflowRunId: resolvedWorkflowRunId,
2241
+ transferKind: 'upstream_remediation',
2242
+ objective: normalizedWrapperName || normalizedWrapperContractRef || 'Wrapper execution request',
2243
+ requestedOutcome: normalizedHandoffNotes || normalizedWrapperContractRef || 'Prepare wrapper execution request.',
2244
+ target: normalizedTargetAgent
2245
+ ? {
2246
+ intent: 'upstream_remediation',
2247
+ recipient_mode: 'agent_session',
2248
+ preferred_agent_session_id: normalizedTargetAgent,
2249
+ preferred_role_key: normalizedTargetAgent,
2250
+ }
2251
+ : {
2252
+ intent: 'upstream_remediation',
2253
+ recipient_mode: 'role',
2254
+ preferred_role_key: 'wrapper_execution',
2255
+ },
2256
+ artifacts: normalizedExecutionScope,
2257
+ issues: normalizedAllowedBlastRadius,
2258
+ expectedEvidence: normalizedRequiredEvidence,
2259
+ preferredModes: ['bundle', 'artifact_refs', 'inline_payload'],
2260
+ capabilities: {
2261
+ wrapper_execution_required: Boolean(normalizedWrapperExecutionRequired),
2262
+ allowed_blast_radius: normalizedAllowedBlastRadius,
2263
+ },
2264
+ senderAgentSessionId: normalizedSubmittedBy,
2265
+ senderActorSessionId: null,
2266
+ messageKind: 'handoff',
2267
+ subject: normalizedWrapperName || normalizedWrapperContractRef || 'Wrapper execution request',
2268
+ bodyMarkdown: normalizedHandoffNotes || normalizedWrapperContractRef || normalizedWrapperName,
2269
+ metadata: {
2270
+ ...normalizedMetadata,
2271
+ source: 'requestModernizationWrapperExecution',
2272
+ modernization_packet_id: resolvedModernizationPacketId,
2273
+ wrapper_execution_required: Boolean(normalizedWrapperExecutionRequired),
2274
+ },
2275
+ });
2276
+ }
2277
+ const transferPayload = isPlainObject(transferResult) ? transferResult : {};
2278
+
2279
+ const transferPacketId = cleanText(wrapperRequestRecord?.transfer_packet_id)
2280
+ || cleanText(wrapperRequestRecord?.work_transfer_packet_id)
2281
+ || cleanText(wrapperRequestRecord?.workTransferPacketId)
2282
+ || cleanText(transferPayload.work_transfer_packet?.work_transfer_packet_id)
2283
+ || cleanText(transferPayload.work_transfer_packet_id)
2284
+ || cleanText(transferPayload.transfer_packet_id)
2285
+ || cleanText(transferPayload.packet_id)
2286
+ || null;
2287
+
2288
+ const transferChannelInputId = cleanText(transfer_channel_id)
2289
+ || cleanText(transferChannelId)
2290
+ || cleanText(channel_id)
2291
+ || cleanText(channelId);
2292
+ const channelSurface = transferChannelInputId
2293
+ ? (typeof client.resumeTransferChannel === 'function'
2294
+ ? client.resumeTransferChannel.bind(client)
2295
+ : null)
2296
+ : (transferPacketId && typeof client.openTransferChannel === 'function'
2297
+ ? client.openTransferChannel.bind(client)
2298
+ : null);
2299
+ if (!channelSurface && (transferChannelInputId || transferPacketId)) {
2300
+ missingSurfaces.push(transferChannelInputId ? 'resumeTransferChannel' : 'openTransferChannel');
2301
+ }
2302
+ const channelResult = channelSurface && transferPacketId
2303
+ ? await channelSurface({
2304
+ transferChannelId: transferChannelInputId || undefined,
2305
+ workTransferPacketId: transferPacketId,
2306
+ workflowRunId: resolvedWorkflowRunId,
2307
+ channelKind: 'bidirectional',
2308
+ upstreamAgentSessionId: normalizedSubmittedBy,
2309
+ downstreamAgentSessionId: normalizedTargetAgent || undefined,
2310
+ evidenceRequiredForClosure: true,
2311
+ metadata: {
2312
+ ...normalizedMetadata,
2313
+ source: 'requestModernizationWrapperExecution',
2314
+ },
2315
+ })
2316
+ : null;
2317
+ const channelPayload = isPlainObject(channelResult) ? channelResult : {};
2318
+ const resolvedChannelId = cleanText(channelPayload.transfer_channel_id)
2319
+ || cleanText(channelPayload.channel_id)
2320
+ || cleanText(channelPayload.transfer_channel?.transfer_channel_id)
2321
+ || cleanText(channelPayload.communication_transfer_channel?.transfer_channel_id)
2322
+ || transferChannelInputId
2323
+ || null;
2324
+
2325
+ const ownershipSurface = normalizedTargetAgent && resolvedChannelId && typeof client.assignCollaborationOwnership === 'function'
2326
+ ? client.assignCollaborationOwnership.bind(client)
2327
+ : null;
2328
+ if (normalizedTargetAgent && !ownershipSurface) missingSurfaces.push('assignCollaborationOwnership');
2329
+ const ownershipResult = ownershipSurface
2330
+ ? await ownershipSurface({
2331
+ transferChannelId: resolvedChannelId,
2332
+ workTransferPacketId: transferPacketId,
2333
+ workflowRunId: resolvedWorkflowRunId,
2334
+ participantRole: 'wrapper_executor',
2335
+ ownerAgentSessionId: normalizedTargetAgent,
2336
+ ownerActorSessionId: null,
2337
+ ownerLabel: normalizedTargetAgent,
2338
+ assignmentState: 'assigned',
2339
+ assignmentReason: normalizedWrapperName || normalizedWrapperContractRef || normalizedHandoffNotes,
2340
+ currentPhase: 'wrapper_execution_request',
2341
+ assignedByAgentSessionId: normalizedSubmittedBy,
2342
+ assignedByActorSessionId: null,
2343
+ metadata: {
2344
+ ...normalizedMetadata,
2345
+ source: 'requestModernizationWrapperExecution',
2346
+ },
2347
+ })
2348
+ : null;
2349
+ const ownershipPayload = isPlainObject(ownershipResult) ? ownershipResult : {};
2350
+
2351
+ const watchSurface = resolvedChannelId && typeof client.startMessageWatch === 'function'
2352
+ ? client.startMessageWatch.bind(client)
2353
+ : null;
2354
+ if (resolvedChannelId && !watchSurface) missingSurfaces.push('startMessageWatch');
2355
+ const watchResult = watchSurface
2356
+ ? await watchSurface({
2357
+ transferChannelId: resolvedChannelId,
2358
+ workTransferPacketId: transferPacketId,
2359
+ workflowRunId: resolvedWorkflowRunId,
2360
+ watchingAgentRole: normalizedSubmittedBy,
2361
+ expectedFromRole: normalizedTargetAgent || 'wrapper_executor',
2362
+ expectedMessageKind: 'response',
2363
+ watchType: 'expected_peer_message',
2364
+ watchingAgentSessionId: normalizedSubmittedBy,
2365
+ expectedPayload: {
2366
+ modernization_packet_id: resolvedModernizationPacketId,
2367
+ expected_acknowledgement: 'wrapper execution request received',
2368
+ },
2369
+ currentStatus: 'watching',
2370
+ operatorNudge: normalizedHandoffNotes || normalizedWrapperContractRef || normalizedWrapperName,
2371
+ metadata: {
2372
+ ...normalizedMetadata,
2373
+ source: 'requestModernizationWrapperExecution',
2374
+ },
2375
+ })
2376
+ : null;
2377
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
2378
+
2379
+ const heartbeatSurface = resolvedChannelId && typeof client.postCollaborationHeartbeat === 'function'
2380
+ ? client.postCollaborationHeartbeat.bind(client)
2381
+ : null;
2382
+ if (resolvedChannelId && !heartbeatSurface) missingSurfaces.push('postCollaborationHeartbeat');
2383
+ const heartbeatResult = heartbeatSurface
2384
+ ? await heartbeatSurface({
2385
+ transferChannelId: resolvedChannelId,
2386
+ workTransferPacketId: transferPacketId,
2387
+ workflowRunId: resolvedWorkflowRunId,
2388
+ participantRole: normalizedTargetAgent ? 'wrapper_executor' : 'wrapper_planner',
2389
+ currentPhase: 'wrapper_execution_request',
2390
+ currentTaskSummary: normalizedWrapperName || normalizedWrapperContractRef || 'Wrapper execution request',
2391
+ metadata: {
2392
+ ...normalizedMetadata,
2393
+ source: 'requestModernizationWrapperExecution',
2394
+ },
2395
+ }).catch(() => null)
2396
+ : null;
2397
+ const heartbeatPayload = isPlainObject(heartbeatResult) ? heartbeatResult : {};
2398
+
2399
+ const transferChannelProjectionSurface = includeTransferChannelProjection && resolvedChannelId
2400
+ ? (typeof client.getTransferChannelProjection === 'function'
2401
+ ? client.getTransferChannelProjection.bind(client)
2402
+ : typeof client.getLogaTransferChannelThreadProjection === 'function'
2403
+ ? client.getLogaTransferChannelThreadProjection.bind(client)
2404
+ : null)
2405
+ : null;
2406
+ if (includeTransferChannelProjection && resolvedChannelId && !transferChannelProjectionSurface) missingSurfaces.push('getTransferChannelProjection');
2407
+ const transferChannelProjection = transferChannelProjectionSurface && resolvedChannelId
2408
+ ? await transferChannelProjectionSurface(resolvedChannelId).catch(() => null)
2409
+ : null;
2410
+
2411
+ const wrapperExecutionRequestId = cleanText(wrapperRequestRecord?.wrapper_execution_request_id)
2412
+ || cleanText(wrapperRequestRecord?.wrapperExecutionRequestId)
2413
+ || cleanText(wrapperRequestRecord?.execution_request_id)
2414
+ || cleanText(wrapperRequestRecord?.executionRequestId)
2415
+ || null;
2416
+ const expectedAcknowledgement = cleanText(watchPayload.expected_message_kind)
2417
+ || cleanText(watchPayload.message_watch?.expected_message_kind)
2418
+ || cleanText(watchPayload.message_watch?.expected_acknowledgement)
2419
+ || (normalizedTargetAgent ? 'acknowledgement' : null);
2420
+ const ownershipAssignmentId = cleanText(ownershipPayload.collaboration_ownership_assignment_id)
2421
+ || cleanText(ownershipPayload.ownership_assignment_id)
2422
+ || cleanText(ownershipPayload.collaboration_ownership_assignment?.collaboration_ownership_assignment_id)
2423
+ || cleanText(ownershipPayload.collaboration_ownership_assignment?.ownership_assignment_id)
2424
+ || null;
2425
+ const watchId = cleanText(watchPayload.message_watch_id)
2426
+ || cleanText(watchPayload.watch_id)
2427
+ || cleanText(watchPayload.message_watch?.message_watch_id)
2428
+ || cleanText(watchPayload.message_watch?.watch_id)
2429
+ || null;
2430
+ const heartbeatStatus = cleanText(heartbeatPayload.collaboration_heartbeat?.activity_state)
2431
+ || cleanText(heartbeatPayload.activity_state)
2432
+ || cleanText(heartbeatPayload.status)
2433
+ || cleanText(heartbeatPayload.collaboration_heartbeat?.status)
2434
+ || null;
2435
+ const wrapperExecutionRequiredResolved = Boolean(normalizedWrapperExecutionRequired);
2436
+
2437
+ return {
2438
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
2439
+ project_id: resolvedProjectId || null,
2440
+ modernization_packet_id: resolvedModernizationPacketId,
2441
+ wrapper_execution_request_id: wrapperExecutionRequestId || null,
2442
+ transfer_packet_id: transferPacketId,
2443
+ target_agent: normalizedTargetAgent || null,
2444
+ channel_id: resolvedChannelId,
2445
+ ownership_assignment_id: ownershipAssignmentId,
2446
+ watch_id: watchId,
2447
+ expected_acknowledgement: expectedAcknowledgement,
2448
+ wrapper_execution_required: wrapperExecutionRequiredResolved,
2449
+ heartbeat_status: heartbeatStatus,
2450
+ operator_projection_metadata: {
2451
+ portfolio_bundle: portfolioBundle,
2452
+ project_roadmap_summary: projectRoadmapSummary,
2453
+ project_roadmap_active_item: projectActiveItem,
2454
+ modernization_packet_record: packetRecordPayload,
2455
+ wrapper_execution_request_record: wrapperRequestRecord,
2456
+ transfer: transferPayload,
2457
+ channel: channelPayload,
2458
+ ownership_assignment: ownershipPayload,
2459
+ message_watch: watchPayload,
2460
+ heartbeat: heartbeatPayload,
2461
+ transfer_channel_projection: transferChannelProjection,
2462
+ },
2463
+ missing_surfaces: [...new Set(missingSurfaces)],
2464
+ project: projectPayload,
2465
+ modernization_packet_record: packetRecordPayload,
2466
+ wrapper_execution_request_record: wrapperRequestRecord,
2467
+ transfer: transferPayload,
2468
+ channel: channelPayload,
2469
+ ownership_assignment: ownershipPayload,
2470
+ message_watch: watchPayload,
2471
+ heartbeat: heartbeatPayload,
2472
+ };
2473
+ }
2474
+
2475
+ export async function getModernizationWrapperEvidence(client, {
2476
+ projectIdentifier,
2477
+ projectId,
2478
+ relatedProjectId,
2479
+ related_project_id,
2480
+ startWorkBody = {},
2481
+ startWorkRequest = {},
2482
+ resumeProjectWorkOptions = {},
2483
+ modernizationPacket = {},
2484
+ modernization_packet = {},
2485
+ modernizationPacketId,
2486
+ modernization_packet_id,
2487
+ packetId,
2488
+ packet_id,
2489
+ wrapperExecutionRequest = {},
2490
+ wrapper_execution_request = {},
2491
+ wrapperExecutionRequestId,
2492
+ wrapper_execution_request_id,
2493
+ wrapperExecutionId,
2494
+ wrapper_execution_id,
2495
+ sourceRef,
2496
+ source_ref,
2497
+ includeOperations = true,
2498
+ include_operations = true,
2499
+ includeFileManifest = true,
2500
+ include_file_manifest = true,
2501
+ includeVerificationSummary = true,
2502
+ include_verification_summary = true,
2503
+ includeProjection = true,
2504
+ include_projection = true,
2505
+ includePortfolioBundle = true,
2506
+ includeProjectRoadmap = true,
2507
+ includeProjectActiveItem = true,
2508
+ metadata = {},
2509
+ } = {}) {
2510
+ const missingSurfaces = [];
2511
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
2512
+ const normalizedPacket = isPlainObject(modernization_packet)
2513
+ ? modernization_packet
2514
+ : (isPlainObject(modernizationPacket) ? modernizationPacket : {});
2515
+ const normalizedWrapperExecutionRequest = isPlainObject(wrapper_execution_request)
2516
+ ? wrapper_execution_request
2517
+ : (isPlainObject(wrapperExecutionRequest) ? wrapperExecutionRequest : {});
2518
+ const normalizedProjectReference = cleanText(projectIdentifier)
2519
+ || cleanText(projectId)
2520
+ || cleanText(relatedProjectId)
2521
+ || cleanText(related_project_id)
2522
+ || cleanText(normalizedPacket.project_id)
2523
+ || cleanText(normalizedPacket.projectId)
2524
+ || cleanText(normalizedPacket.related_project_id)
2525
+ || cleanText(normalizedPacket.relatedProjectId)
2526
+ || cleanText(normalizedWrapperExecutionRequest.project_id)
2527
+ || cleanText(normalizedWrapperExecutionRequest.projectId)
2528
+ || cleanText(normalizedWrapperExecutionRequest.related_project_id)
2529
+ || cleanText(normalizedWrapperExecutionRequest.relatedProjectId);
2530
+ const normalizedModernizationPacketId = cleanText(modernization_packet_id)
2531
+ || cleanText(modernizationPacketId)
2532
+ || cleanText(packet_id)
2533
+ || cleanText(packetId)
2534
+ || cleanText(normalizedPacket.modernization_packet_id)
2535
+ || cleanText(normalizedPacket.modernizationPacketId)
2536
+ || cleanText(normalizedPacket.packet_id)
2537
+ || cleanText(normalizedPacket.packetId)
2538
+ || cleanText(normalizedWrapperExecutionRequest.modernization_packet_id)
2539
+ || cleanText(normalizedWrapperExecutionRequest.modernizationPacketId)
2540
+ || cleanText(normalizedWrapperExecutionRequest.packet_id)
2541
+ || cleanText(normalizedWrapperExecutionRequest.packetId);
2542
+ const normalizedWrapperExecutionRequestId = cleanText(wrapper_execution_request_id)
2543
+ || cleanText(wrapperExecutionRequestId)
2544
+ || cleanText(normalizedWrapperExecutionRequest.wrapper_execution_request_id)
2545
+ || cleanText(normalizedWrapperExecutionRequest.wrapperExecutionRequestId)
2546
+ || cleanText(normalizedWrapperExecutionRequest.execution_request_id)
2547
+ || cleanText(normalizedWrapperExecutionRequest.executionRequestId);
2548
+ const normalizedWrapperExecutionId = cleanText(wrapper_execution_id)
2549
+ || cleanText(wrapperExecutionId)
2550
+ || cleanText(normalizedWrapperExecutionRequest.wrapper_execution_id)
2551
+ || cleanText(normalizedWrapperExecutionRequest.wrapperExecutionId)
2552
+ || cleanText(normalizedWrapperExecutionRequest.execution_id)
2553
+ || cleanText(normalizedWrapperExecutionRequest.executionId)
2554
+ || cleanText(normalizedWrapperExecutionRequest.wrapper_execution_record_id)
2555
+ || cleanText(normalizedWrapperExecutionRequest.wrapperExecutionRecordId);
2556
+ const normalizedSourceRef = cleanText(source_ref)
2557
+ || cleanText(sourceRef)
2558
+ || cleanText(normalizedPacket.source_ref)
2559
+ || cleanText(normalizedPacket.sourceRef)
2560
+ || cleanText(normalizedWrapperExecutionRequest.source_ref)
2561
+ || cleanText(normalizedWrapperExecutionRequest.sourceRef)
2562
+ || normalizedModernizationPacketId
2563
+ || normalizedWrapperExecutionRequestId
2564
+ || normalizedWrapperExecutionId;
2565
+ const normalizedIncludeOperations = include_operations ?? includeOperations ?? true;
2566
+ const normalizedIncludeFileManifest = include_file_manifest ?? includeFileManifest ?? true;
2567
+ const normalizedIncludeVerificationSummary = include_verification_summary ?? includeVerificationSummary ?? true;
2568
+ const normalizedIncludeProjection = include_projection ?? includeProjection ?? true;
2569
+
2570
+ const pickSurface = (candidateNames) => {
2571
+ for (const candidateName of candidateNames) {
2572
+ if (typeof client[candidateName] === 'function') {
2573
+ return client[candidateName].bind(client);
2574
+ }
2575
+ }
2576
+ for (const candidateName of candidateNames) {
2577
+ missingSurfaces.push(candidateName);
2578
+ }
2579
+ return null;
2580
+ };
2581
+
2582
+ let continuation = null;
2583
+ let startWorkResult = null;
2584
+ if (normalizedProjectReference) {
2585
+ if (typeof client.resumeProjectWork === 'function') {
2586
+ continuation = await client.resumeProjectWork({
2587
+ projectIdentifier: normalizedProjectReference,
2588
+ projectId: normalizedProjectReference,
2589
+ requireClaim: false,
2590
+ ...resumeProjectWorkOptions,
2591
+ });
2592
+ } else {
2593
+ missingSurfaces.push('resumeProjectWork');
2594
+ }
2595
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
2596
+ if (typeof client.startWork === 'function') {
2597
+ startWorkResult = await client.startWork({
2598
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
2599
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
2600
+ });
2601
+ } else {
2602
+ missingSurfaces.push('startWork');
2603
+ }
2604
+ }
2605
+
2606
+ const projectPayload = isPlainObject(continuation?.project)
2607
+ ? continuation.project
2608
+ : isPlainObject(startWorkResult?.project)
2609
+ ? startWorkResult.project
2610
+ : isPlainObject(continuation?.summary)
2611
+ ? continuation.summary
2612
+ : {};
2613
+ const resolvedProjectId = cleanText(projectPayload.project_id)
2614
+ || cleanText(projectPayload.projectId)
2615
+ || normalizedProjectReference;
2616
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
2617
+ || cleanText(projectPayload.workflowId)
2618
+ || cleanText(continuation?.workflow_id)
2619
+ || cleanText(startWorkResult?.workflow_id);
2620
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
2621
+ || cleanText(projectPayload.workflowRunId)
2622
+ || cleanText(continuation?.workflow_run_id)
2623
+ || cleanText(startWorkResult?.workflow_run_id)
2624
+ || cleanText(startWorkResult?.workflowRunId);
2625
+
2626
+ const portfolioBundle = includePortfolioBundle && typeof client.getPortfolioBundle === 'function'
2627
+ ? await client.getPortfolioBundle().catch(() => null)
2628
+ : null;
2629
+ const projectRoadmapSummary = resolvedProjectId && includeProjectRoadmap && typeof client.getProjectRoadmapSummary === 'function'
2630
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
2631
+ : null;
2632
+ const projectActiveItem = resolvedProjectId && includeProjectActiveItem && typeof client.getProjectRoadmapActiveItem === 'function'
2633
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
2634
+ : null;
2635
+
2636
+ let modernizationPacketRecord = null;
2637
+ const packetLookupSurface = pickSurface(['getModernizationWorkPacketRecord', 'getModernizationPacketRecord']);
2638
+ if (packetLookupSurface) {
2639
+ modernizationPacketRecord = await packetLookupSurface({
2640
+ projectId: resolvedProjectId,
2641
+ workflowId: resolvedWorkflowId,
2642
+ workflowRunId: resolvedWorkflowRunId,
2643
+ modernizationPacketId: normalizedModernizationPacketId,
2644
+ packetId: normalizedModernizationPacketId,
2645
+ sourceRef: normalizedSourceRef,
2646
+ metadata: {
2647
+ ...normalizedMetadata,
2648
+ source: 'getModernizationWrapperEvidence',
2649
+ },
2650
+ }).catch(() => null);
2651
+ }
2652
+
2653
+ const packetRecordPayload = isPlainObject(modernizationPacketRecord) ? modernizationPacketRecord : {};
2654
+ const resolvedModernizationPacketId = cleanText(packetRecordPayload.modernization_packet_id)
2655
+ || cleanText(packetRecordPayload.modernizationPacketId)
2656
+ || cleanText(packetRecordPayload.work_packet_id)
2657
+ || cleanText(packetRecordPayload.workPacketId)
2658
+ || normalizedModernizationPacketId
2659
+ || null;
2660
+ let wrapperExecutionRequestRecord = null;
2661
+ const wrapperRequestLookupSurface = pickSurface([
2662
+ 'getModernizationWrapperExecutionRequestRecord',
2663
+ 'getWrapperExecutionRequestRecord',
2664
+ 'getModernizationWrapperExecutionRequest',
2665
+ 'getWrapperExecutionRequest',
2666
+ ]);
2667
+ if (wrapperRequestLookupSurface) {
2668
+ wrapperExecutionRequestRecord = await wrapperRequestLookupSurface({
2669
+ projectId: resolvedProjectId,
2670
+ workflowId: resolvedWorkflowId,
2671
+ workflowRunId: resolvedWorkflowRunId,
2672
+ modernizationPacketId: resolvedModernizationPacketId,
2673
+ wrapperExecutionRequestId: normalizedWrapperExecutionRequestId,
2674
+ wrapperExecutionId: normalizedWrapperExecutionId,
2675
+ sourceRef: normalizedSourceRef,
2676
+ metadata: {
2677
+ ...normalizedMetadata,
2678
+ source: 'getModernizationWrapperEvidence',
2679
+ },
2680
+ }).catch(() => null);
2681
+ }
2682
+
2683
+ const requestRecordPayload = isPlainObject(wrapperExecutionRequestRecord) ? wrapperExecutionRequestRecord : {};
2684
+ const resolvedWrapperExecutionRequestId = cleanText(requestRecordPayload.wrapper_execution_request_id)
2685
+ || cleanText(requestRecordPayload.wrapperExecutionRequestId)
2686
+ || cleanText(requestRecordPayload.execution_request_id)
2687
+ || cleanText(requestRecordPayload.executionRequestId)
2688
+ || normalizedWrapperExecutionRequestId
2689
+ || null;
2690
+
2691
+ let wrapperExecutionEvidenceBundle = null;
2692
+ const wrapperEvidenceLookupSurface = pickSurface([
2693
+ 'getWrapperExecutionEvidenceBundle',
2694
+ 'getLatestWrapperExecutionEvidenceBundle',
2695
+ 'getModernizationWrapperEvidenceBundle',
2696
+ 'getModernizationWrapperExecutionEvidenceBundle',
2697
+ ]);
2698
+ if (wrapperEvidenceLookupSurface) {
2699
+ wrapperExecutionEvidenceBundle = await wrapperEvidenceLookupSurface({
2700
+ projectId: resolvedProjectId,
2701
+ workflowId: resolvedWorkflowId,
2702
+ workflowRunId: resolvedWorkflowRunId,
2703
+ modernizationPacketId: resolvedModernizationPacketId,
2704
+ wrapperExecutionRequestId: resolvedWrapperExecutionRequestId,
2705
+ wrapperExecutionId: normalizedWrapperExecutionId,
2706
+ includeOperations: Boolean(normalizedIncludeOperations),
2707
+ includeFileManifest: Boolean(normalizedIncludeFileManifest),
2708
+ includeVerificationSummary: Boolean(normalizedIncludeVerificationSummary),
2709
+ includeProjection: Boolean(normalizedIncludeProjection),
2710
+ metadata: {
2711
+ ...normalizedMetadata,
2712
+ source: 'getModernizationWrapperEvidence',
2713
+ },
2714
+ }).catch(() => null);
2715
+ }
2716
+
2717
+ const bundlePayload = isPlainObject(wrapperExecutionEvidenceBundle) ? wrapperExecutionEvidenceBundle : {};
2718
+ let wrapperExecutionRecord = isPlainObject(bundlePayload.wrapper_execution_record)
2719
+ ? bundlePayload.wrapper_execution_record
2720
+ : isPlainObject(bundlePayload.wrapperExecutionRecord)
2721
+ ? bundlePayload.wrapperExecutionRecord
2722
+ : null;
2723
+ let wrapperOperationRecords = Array.isArray(bundlePayload.wrapper_operation_records)
2724
+ ? bundlePayload.wrapper_operation_records.filter((record) => isPlainObject(record))
2725
+ : Array.isArray(bundlePayload.wrapperOperationRecords)
2726
+ ? bundlePayload.wrapperOperationRecords.filter((record) => isPlainObject(record))
2727
+ : [];
2728
+ let wrapperFileManifest = isPlainObject(bundlePayload.wrapper_file_manifest)
2729
+ ? bundlePayload.wrapper_file_manifest
2730
+ : isPlainObject(bundlePayload.wrapperFileManifest)
2731
+ ? bundlePayload.wrapperFileManifest
2732
+ : null;
2733
+ let wrapperVerificationSummary = isPlainObject(bundlePayload.wrapper_verification_summary)
2734
+ ? bundlePayload.wrapper_verification_summary
2735
+ : isPlainObject(bundlePayload.wrapperVerificationSummary)
2736
+ ? bundlePayload.wrapperVerificationSummary
2737
+ : null;
2738
+
2739
+ if (!wrapperExecutionEvidenceBundle) {
2740
+ if (!wrapperExecutionRecord) {
2741
+ const wrapperRecordSurface = pickSurface([
2742
+ 'getWrapperExecutionRecord',
2743
+ 'getModernizationWrapperExecutionRecord',
2744
+ ]);
2745
+ if (wrapperRecordSurface) {
2746
+ const wrapperRecordResult = await wrapperRecordSurface({
2747
+ projectId: resolvedProjectId,
2748
+ workflowId: resolvedWorkflowId,
2749
+ workflowRunId: resolvedWorkflowRunId,
2750
+ modernizationPacketId: resolvedModernizationPacketId,
2751
+ wrapperExecutionRequestId: resolvedWrapperExecutionRequestId,
2752
+ wrapperExecutionId: normalizedWrapperExecutionId,
2753
+ sourceRef: normalizedSourceRef,
2754
+ metadata: {
2755
+ ...normalizedMetadata,
2756
+ source: 'getModernizationWrapperEvidence',
2757
+ },
2758
+ }).catch(() => null);
2759
+ if (isPlainObject(wrapperRecordResult)) {
2760
+ wrapperExecutionRecord = wrapperRecordResult;
2761
+ }
2762
+ }
2763
+ }
2764
+
2765
+ if (normalizedIncludeOperations && wrapperOperationRecords.length === 0) {
2766
+ const wrapperOperationSurface = pickSurface([
2767
+ 'getWrapperExecutionOperationLog',
2768
+ 'getModernizationWrapperExecutionOperationLog',
2769
+ 'listWrapperExecutionOperations',
2770
+ ]);
2771
+ if (wrapperOperationSurface) {
2772
+ const wrapperOperationResult = await wrapperOperationSurface({
2773
+ projectId: resolvedProjectId,
2774
+ workflowId: resolvedWorkflowId,
2775
+ workflowRunId: resolvedWorkflowRunId,
2776
+ modernizationPacketId: resolvedModernizationPacketId,
2777
+ wrapperExecutionRequestId: resolvedWrapperExecutionRequestId,
2778
+ wrapperExecutionId: normalizedWrapperExecutionId,
2779
+ includeProjection: Boolean(normalizedIncludeProjection),
2780
+ metadata: {
2781
+ ...normalizedMetadata,
2782
+ source: 'getModernizationWrapperEvidence',
2783
+ },
2784
+ }).catch(() => null);
2785
+ if (Array.isArray(wrapperOperationResult)) {
2786
+ wrapperOperationRecords = wrapperOperationResult.filter((record) => isPlainObject(record));
2787
+ } else if (isPlainObject(wrapperOperationResult)) {
2788
+ const maybeRecords = Array.isArray(wrapperOperationResult.wrapper_operation_records)
2789
+ ? wrapperOperationResult.wrapper_operation_records
2790
+ : Array.isArray(wrapperOperationResult.operation_records)
2791
+ ? wrapperOperationResult.operation_records
2792
+ : [];
2793
+ wrapperOperationRecords = maybeRecords.filter((record) => isPlainObject(record));
2794
+ }
2795
+ }
2796
+ }
2797
+
2798
+ if (normalizedIncludeFileManifest && !wrapperFileManifest) {
2799
+ const wrapperFileManifestSurface = pickSurface([
2800
+ 'getWrapperExecutionFileManifest',
2801
+ 'getModernizationWrapperExecutionFileManifest',
2802
+ ]);
2803
+ if (wrapperFileManifestSurface) {
2804
+ const wrapperFileManifestResult = await wrapperFileManifestSurface({
2805
+ projectId: resolvedProjectId,
2806
+ workflowId: resolvedWorkflowId,
2807
+ workflowRunId: resolvedWorkflowRunId,
2808
+ modernizationPacketId: resolvedModernizationPacketId,
2809
+ wrapperExecutionRequestId: resolvedWrapperExecutionRequestId,
2810
+ wrapperExecutionId: normalizedWrapperExecutionId,
2811
+ metadata: {
2812
+ ...normalizedMetadata,
2813
+ source: 'getModernizationWrapperEvidence',
2814
+ },
2815
+ }).catch(() => null);
2816
+ if (isPlainObject(wrapperFileManifestResult)) {
2817
+ wrapperFileManifest = wrapperFileManifestResult;
2818
+ }
2819
+ }
2820
+ }
2821
+
2822
+ if (normalizedIncludeVerificationSummary && !wrapperVerificationSummary) {
2823
+ const wrapperVerificationSurface = pickSurface([
2824
+ 'getWrapperExecutionVerificationSummary',
2825
+ 'getModernizationWrapperExecutionVerificationSummary',
2826
+ ]);
2827
+ if (wrapperVerificationSurface) {
2828
+ const wrapperVerificationResult = await wrapperVerificationSurface({
2829
+ projectId: resolvedProjectId,
2830
+ workflowId: resolvedWorkflowId,
2831
+ workflowRunId: resolvedWorkflowRunId,
2832
+ modernizationPacketId: resolvedModernizationPacketId,
2833
+ wrapperExecutionRequestId: resolvedWrapperExecutionRequestId,
2834
+ wrapperExecutionId: normalizedWrapperExecutionId,
2835
+ metadata: {
2836
+ ...normalizedMetadata,
2837
+ source: 'getModernizationWrapperEvidence',
2838
+ },
2839
+ }).catch(() => null);
2840
+ if (isPlainObject(wrapperVerificationResult)) {
2841
+ wrapperVerificationSummary = wrapperVerificationResult;
2842
+ }
2843
+ }
2844
+ }
2845
+ }
2846
+
2847
+ const wrapperExecutionIdResolved = cleanText(wrapperExecutionRecord?.execution_id)
2848
+ || cleanText(wrapperExecutionRecord?.executionId)
2849
+ || cleanText(bundlePayload.wrapper_execution_persistence?.wrapper_execution_record_id)
2850
+ || cleanText(bundlePayload.wrapper_execution_persistence?.wrapperExecutionRecordId)
2851
+ || normalizedWrapperExecutionId
2852
+ || null;
2853
+ const executionStatus = cleanText(wrapperExecutionRecord?.status)
2854
+ || cleanText(bundlePayload.wrapper_execution_record?.status)
2855
+ || cleanText(bundlePayload.wrapperExecutionRecord?.status)
2856
+ || null;
2857
+ const verificationStatus = cleanText(wrapperVerificationSummary?.verification_status)
2858
+ || cleanText(wrapperVerificationSummary?.verificationStatus)
2859
+ || cleanText(bundlePayload.wrapper_verification_summary?.verification_status)
2860
+ || cleanText(bundlePayload.wrapperVerificationSummary?.verificationStatus)
2861
+ || null;
2862
+
2863
+ const filesCreated = Array.isArray(wrapperFileManifest?.files_created)
2864
+ ? wrapperFileManifest.files_created
2865
+ : Array.isArray(wrapperFileManifest?.filesCreated)
2866
+ ? wrapperFileManifest.filesCreated
2867
+ : [];
2868
+ const filesModified = Array.isArray(wrapperFileManifest?.files_modified)
2869
+ ? wrapperFileManifest.files_modified
2870
+ : Array.isArray(wrapperFileManifest?.filesModified)
2871
+ ? wrapperFileManifest.filesModified
2872
+ : [];
2873
+ const filesCreatedOrModified = cleanList([...filesCreated, ...filesModified]);
2874
+
2875
+ const collectedEvidenceRefs = [];
2876
+ const collectEvidenceRefs = (value) => {
2877
+ if (Array.isArray(value)) {
2878
+ for (const item of value) {
2879
+ if (item !== null && item !== undefined && item !== '') {
2880
+ collectedEvidenceRefs.push(item);
2881
+ }
2882
+ }
2883
+ return;
2884
+ }
2885
+ if (value !== null && value !== undefined && value !== '') {
2886
+ collectedEvidenceRefs.push(value);
2887
+ }
2888
+ };
2889
+ collectEvidenceRefs(bundlePayload.evidence_refs);
2890
+ collectEvidenceRefs(bundlePayload.evidenceRefs);
2891
+ collectEvidenceRefs(wrapperExecutionRecord?.evidence_refs);
2892
+ collectEvidenceRefs(wrapperExecutionRecord?.evidenceRefs);
2893
+ collectEvidenceRefs(wrapperVerificationSummary?.evidence_refs);
2894
+ collectEvidenceRefs(wrapperVerificationSummary?.evidenceRefs);
2895
+ collectEvidenceRefs(requestRecordPayload.evidence_refs);
2896
+ collectEvidenceRefs(requestRecordPayload.evidenceRefs);
2897
+ collectEvidenceRefs(packetRecordPayload.evidence_refs);
2898
+ collectEvidenceRefs(packetRecordPayload.evidenceRefs);
2899
+ if (Array.isArray(wrapperOperationRecords)) {
2900
+ for (const record of wrapperOperationRecords) {
2901
+ collectEvidenceRefs(record?.evidence_ref);
2902
+ collectEvidenceRefs(record?.evidenceRefs);
2903
+ collectEvidenceRefs(record?.evidence_refs);
2904
+ }
2905
+ }
2906
+ const uniqueEvidenceRefs = [];
2907
+ const seenEvidenceRefKeys = new Set();
2908
+ for (const evidenceRef of collectedEvidenceRefs) {
2909
+ const key = typeof evidenceRef === 'string'
2910
+ ? evidenceRef.trim()
2911
+ : JSON.stringify(evidenceRef);
2912
+ if (!key || seenEvidenceRefKeys.has(key)) continue;
2913
+ seenEvidenceRefKeys.add(key);
2914
+ uniqueEvidenceRefs.push(evidenceRef);
2915
+ }
2916
+
2917
+ const transferPacketId = cleanText(wrapperExecutionRequestRecord?.transfer_packet_id)
2918
+ || cleanText(wrapperExecutionRequestRecord?.work_transfer_packet_id)
2919
+ || cleanText(wrapperExecutionRequestRecord?.workTransferPacketId)
2920
+ || cleanText(bundlePayload.transfer_packet_id)
2921
+ || cleanText(bundlePayload.transferPacketId)
2922
+ || null;
2923
+ const transferChannelId = cleanText(wrapperExecutionRequestRecord?.transfer_channel_id)
2924
+ || cleanText(wrapperExecutionRequestRecord?.channel_id)
2925
+ || cleanText(wrapperExecutionRequestRecord?.channelId)
2926
+ || cleanText(bundlePayload.transfer_channel_id)
2927
+ || cleanText(bundlePayload.transferChannelId)
2928
+ || null;
2929
+
2930
+ let transferPacketProjection = null;
2931
+ if (normalizedIncludeProjection && transferPacketId) {
2932
+ if (typeof client.getTransferPacketProjection === 'function') {
2933
+ transferPacketProjection = await client.getTransferPacketProjection(transferPacketId).catch(() => null);
2934
+ } else {
2935
+ missingSurfaces.push('getTransferPacketProjection');
2936
+ }
2937
+ }
2938
+ let transferChannelProjection = null;
2939
+ if (normalizedIncludeProjection && transferChannelId) {
2940
+ const transferChannelProjectionSurface = typeof client.getTransferChannelProjection === 'function'
2941
+ ? client.getTransferChannelProjection.bind(client)
2942
+ : typeof client.getLogaTransferChannelThreadProjection === 'function'
2943
+ ? client.getLogaTransferChannelThreadProjection.bind(client)
2944
+ : null;
2945
+ if (!transferChannelProjectionSurface) {
2946
+ missingSurfaces.push('getTransferChannelProjection');
2947
+ } else {
2948
+ transferChannelProjection = await transferChannelProjectionSurface(transferChannelId).catch(() => null);
2949
+ }
2950
+ }
2951
+
2952
+ const operationCount = wrapperOperationRecords.length;
2953
+ const gateReady = Boolean(
2954
+ wrapperExecutionRecord
2955
+ && executionStatus === 'completed'
2956
+ && verificationStatus === 'pass'
2957
+ && operationCount > 0
2958
+ && filesCreatedOrModified.length > 0
2959
+ );
2960
+
2961
+ return {
2962
+ status: missingSurfaces.length > 0 ? 'partial' : 'ready',
2963
+ project_id: resolvedProjectId || null,
2964
+ modernization_packet_id: resolvedModernizationPacketId,
2965
+ wrapper_execution_request_id: resolvedWrapperExecutionRequestId || null,
2966
+ wrapper_execution_id: wrapperExecutionIdResolved,
2967
+ execution_status: executionStatus,
2968
+ operation_count: operationCount,
2969
+ files_created_or_modified: filesCreatedOrModified,
2970
+ verification_status: verificationStatus,
2971
+ gate_ready: gateReady,
2972
+ evidence_refs: uniqueEvidenceRefs,
2973
+ operator_projection_metadata: {
2974
+ portfolio_bundle: portfolioBundle,
2975
+ project_roadmap_summary: projectRoadmapSummary,
2976
+ project_roadmap_active_item: projectActiveItem,
2977
+ modernization_packet_record: modernizationPacketRecord,
2978
+ wrapper_execution_request_record: wrapperExecutionRequestRecord,
2979
+ wrapper_execution_record: wrapperExecutionRecord,
2980
+ wrapper_execution_evidence_bundle: wrapperExecutionEvidenceBundle,
2981
+ wrapper_operation_records: wrapperOperationRecords,
2982
+ wrapper_file_manifest: wrapperFileManifest,
2983
+ wrapper_verification_summary: wrapperVerificationSummary,
2984
+ transfer_packet_projection: transferPacketProjection,
2985
+ transfer_channel_projection: transferChannelProjection,
2986
+ },
2987
+ missing_surfaces: [...new Set(missingSurfaces)],
2988
+ project: projectPayload,
2989
+ modernization_packet_record: modernizationPacketRecord,
2990
+ wrapper_execution_request_record: wrapperExecutionRequestRecord,
2991
+ wrapper_execution_record: wrapperExecutionRecord,
2992
+ wrapper_execution_evidence_bundle: wrapperExecutionEvidenceBundle,
2993
+ wrapper_operation_records: wrapperOperationRecords,
2994
+ wrapper_file_manifest: wrapperFileManifest,
2995
+ wrapper_verification_summary: wrapperVerificationSummary,
2996
+ transfer_packet_projection: transferPacketProjection,
2997
+ transfer_channel_projection: transferChannelProjection,
2998
+ };
2999
+ }
3000
+
3001
+ export async function decideModernizationGate(client, {
3002
+ projectIdentifier,
3003
+ projectId,
3004
+ relatedProjectId,
3005
+ related_project_id,
3006
+ startWorkBody = {},
3007
+ startWorkRequest = {},
3008
+ resumeProjectWorkOptions = {},
3009
+ modernizationPacket = {},
3010
+ modernization_packet = {},
3011
+ modernizationPacketId,
3012
+ modernization_packet_id,
3013
+ packetId,
3014
+ packet_id,
3015
+ wrapperExecutionRequestId,
3016
+ wrapper_execution_request_id,
3017
+ wrapperExecutionId,
3018
+ wrapper_execution_id,
3019
+ sourceRef,
3020
+ source_ref,
3021
+ requiredEvidence = [],
3022
+ required_evidence = [],
3023
+ acceptanceCriteria = [],
3024
+ acceptance_criteria = [],
3025
+ decisionMode,
3026
+ decision_mode,
3027
+ decisionBand,
3028
+ decision_band,
3029
+ reviewer,
3030
+ reviewer_id,
3031
+ assignedReviewer,
3032
+ assigned_reviewer,
3033
+ reviewRequired,
3034
+ review_required,
3035
+ riskLevel,
3036
+ risk_level,
3037
+ rationale,
3038
+ rationaleText,
3039
+ decisionRationale,
3040
+ decision_rationale,
3041
+ recordDecision,
3042
+ record_decision,
3043
+ reviewChannelId,
3044
+ review_channel_id,
3045
+ channelId,
3046
+ channel_id,
3047
+ transferChannelId,
3048
+ transfer_channel_id,
3049
+ implementationItemId,
3050
+ implementation_item_id,
3051
+ submittedBy,
3052
+ submitted_by,
3053
+ includeProjection = true,
3054
+ include_projection = true,
3055
+ metadata = {},
3056
+ } = {}) {
3057
+ const missingSurfaces = [];
3058
+ const normalizedMetadata = isPlainObject(metadata) ? metadata : {};
3059
+ const normalizedPacket = isPlainObject(modernization_packet)
3060
+ ? modernization_packet
3061
+ : (isPlainObject(modernizationPacket) ? modernizationPacket : {});
3062
+ const normalizedProjectReference = cleanText(projectIdentifier)
3063
+ || cleanText(projectId)
3064
+ || cleanText(relatedProjectId)
3065
+ || cleanText(related_project_id)
3066
+ || cleanText(normalizedPacket.project_id)
3067
+ || cleanText(normalizedPacket.projectId)
3068
+ || cleanText(normalizedPacket.related_project_id)
3069
+ || cleanText(normalizedPacket.relatedProjectId);
3070
+ const normalizedModernizationPacketId = cleanText(modernization_packet_id)
3071
+ || cleanText(modernizationPacketId)
3072
+ || cleanText(packet_id)
3073
+ || cleanText(packetId)
3074
+ || cleanText(normalizedPacket.modernization_packet_id)
3075
+ || cleanText(normalizedPacket.modernizationPacketId)
3076
+ || cleanText(normalizedPacket.packet_id)
3077
+ || cleanText(normalizedPacket.packetId);
3078
+ const normalizedWrapperExecutionRequestId = cleanText(wrapper_execution_request_id)
3079
+ || cleanText(wrapperExecutionRequestId);
3080
+ const normalizedWrapperExecutionId = cleanText(wrapper_execution_id)
3081
+ || cleanText(wrapperExecutionId);
3082
+ const normalizedSourceRef = cleanText(source_ref)
3083
+ || cleanText(sourceRef)
3084
+ || cleanText(normalizedPacket.source_ref)
3085
+ || cleanText(normalizedPacket.sourceRef)
3086
+ || normalizedModernizationPacketId
3087
+ || normalizedWrapperExecutionRequestId
3088
+ || normalizedWrapperExecutionId;
3089
+ const normalizedRequiredEvidence = cleanList(required_evidence.length > 0 ? required_evidence : requiredEvidence);
3090
+ const normalizedAcceptanceCriteria = cleanList(acceptance_criteria.length > 0 ? acceptance_criteria : acceptanceCriteria);
3091
+ const normalizedDecisionMode = cleanText(decision_mode) || cleanText(decisionMode) || 'recommend_only';
3092
+ const normalizedDecisionBand = cleanText(decision_band) || cleanText(decisionBand) || null;
3093
+ const normalizedReviewer = cleanText(reviewer_id)
3094
+ || cleanText(reviewer)
3095
+ || cleanText(assigned_reviewer)
3096
+ || cleanText(assignedReviewer)
3097
+ || null;
3098
+ const normalizedReviewRequired = review_required ?? reviewRequired ?? Boolean(normalizedReviewer);
3099
+ const normalizedRiskLevel = cleanText(risk_level) || cleanText(riskLevel) || cleanText(normalizedPacket.risk_level) || cleanText(normalizedPacket.riskLevel) || null;
3100
+ const normalizedRationale = cleanText(decision_rationale)
3101
+ || cleanText(decisionRationale)
3102
+ || cleanText(rationaleText)
3103
+ || cleanText(rationale)
3104
+ || null;
3105
+ const normalizedRecordDecision = record_decision ?? recordDecision ?? normalizedDecisionMode === 'record_decision';
3106
+ const normalizedSubmittedBy = cleanText(submitted_by)
3107
+ || cleanText(submittedBy)
3108
+ || client.agentSessionId
3109
+ || client.actorId
3110
+ || null;
3111
+ const normalizedReviewChannelId = cleanText(review_channel_id)
3112
+ || cleanText(reviewChannelId)
3113
+ || cleanText(channel_id)
3114
+ || cleanText(channelId)
3115
+ || cleanText(transfer_channel_id)
3116
+ || cleanText(transferChannelId)
3117
+ || null;
3118
+
3119
+ const pickSurface = (candidateNames) => {
3120
+ for (const candidateName of candidateNames) {
3121
+ if (typeof client[candidateName] === 'function') {
3122
+ return client[candidateName].bind(client);
3123
+ }
3124
+ }
3125
+ for (const candidateName of candidateNames) {
3126
+ missingSurfaces.push(candidateName);
3127
+ }
3128
+ return null;
3129
+ };
3130
+
3131
+ let continuation = null;
3132
+ let startWorkResult = null;
3133
+ if (normalizedProjectReference) {
3134
+ if (typeof client.resumeProjectWork === 'function') {
3135
+ continuation = await client.resumeProjectWork({
3136
+ projectIdentifier: normalizedProjectReference,
3137
+ projectId: normalizedProjectReference,
3138
+ requireClaim: false,
3139
+ ...resumeProjectWorkOptions,
3140
+ });
3141
+ } else {
3142
+ missingSurfaces.push('resumeProjectWork');
3143
+ }
3144
+ } else if (Object.keys(isPlainObject(startWorkRequest) ? startWorkRequest : {}).length > 0 || Object.keys(isPlainObject(startWorkBody) ? startWorkBody : {}).length > 0) {
3145
+ if (typeof client.startWork === 'function') {
3146
+ startWorkResult = await client.startWork({
3147
+ ...(isPlainObject(startWorkBody) ? startWorkBody : {}),
3148
+ ...(isPlainObject(startWorkRequest) ? startWorkRequest : {}),
3149
+ });
3150
+ } else {
3151
+ missingSurfaces.push('startWork');
3152
+ }
3153
+ }
3154
+
3155
+ const projectPayload = isPlainObject(continuation?.project)
3156
+ ? continuation.project
3157
+ : isPlainObject(startWorkResult?.project)
3158
+ ? startWorkResult.project
3159
+ : isPlainObject(continuation?.summary)
3160
+ ? continuation.summary
3161
+ : {};
3162
+ const resolvedProjectId = cleanText(projectPayload.project_id)
3163
+ || cleanText(projectPayload.projectId)
3164
+ || normalizedProjectReference;
3165
+ const resolvedWorkflowId = cleanText(projectPayload.workflow_id)
3166
+ || cleanText(projectPayload.workflowId)
3167
+ || cleanText(continuation?.workflow_id)
3168
+ || cleanText(startWorkResult?.workflow_id);
3169
+ const resolvedWorkflowRunId = cleanText(projectPayload.workflow_run_id)
3170
+ || cleanText(projectPayload.workflowRunId)
3171
+ || cleanText(continuation?.workflow_run_id)
3172
+ || cleanText(startWorkResult?.workflow_run_id)
3173
+ || cleanText(startWorkResult?.workflowRunId);
3174
+
3175
+ const wrapperEvidence = await client.getModernizationWrapperEvidence({
3176
+ projectIdentifier: resolvedProjectId || normalizedProjectReference,
3177
+ modernizationPacketId: normalizedModernizationPacketId,
3178
+ wrapperExecutionRequestId: normalizedWrapperExecutionRequestId,
3179
+ wrapperExecutionId: normalizedWrapperExecutionId,
3180
+ sourceRef: normalizedSourceRef,
3181
+ includeOperations: true,
3182
+ includeFileManifest: true,
3183
+ includeVerificationSummary: true,
3184
+ includeProjection: Boolean(include_projection ?? includeProjection ?? true),
3185
+ metadata: {
3186
+ ...normalizedMetadata,
3187
+ source: 'decideModernizationGate',
3188
+ },
3189
+ }).catch(() => null);
3190
+ const wrapperEvidencePayload = isPlainObject(wrapperEvidence) ? wrapperEvidence : {};
3191
+
3192
+ let modernizationPacketRecord = isPlainObject(wrapperEvidencePayload.modernization_packet_record)
3193
+ ? wrapperEvidencePayload.modernization_packet_record
3194
+ : null;
3195
+ const packetLookupSurface = typeof client.getModernizationWorkPacketRecord === 'function'
3196
+ ? client.getModernizationWorkPacketRecord.bind(client)
3197
+ : typeof client.getModernizationPacketRecord === 'function'
3198
+ ? client.getModernizationPacketRecord.bind(client)
3199
+ : null;
3200
+ if (!modernizationPacketRecord && packetLookupSurface) {
3201
+ modernizationPacketRecord = await packetLookupSurface({
3202
+ projectId: resolvedProjectId,
3203
+ workflowId: resolvedWorkflowId,
3204
+ workflowRunId: resolvedWorkflowRunId,
3205
+ modernizationPacketId: normalizedModernizationPacketId,
3206
+ packetId: normalizedModernizationPacketId,
3207
+ sourceRef: normalizedSourceRef,
3208
+ metadata: {
3209
+ ...normalizedMetadata,
3210
+ source: 'decideModernizationGate',
3211
+ },
3212
+ }).catch(() => null);
3213
+ }
3214
+ if (!packetLookupSurface) {
3215
+ missingSurfaces.push('getModernizationWorkPacketRecord');
3216
+ missingSurfaces.push('getModernizationPacketRecord');
3217
+ }
3218
+
3219
+ const packetRecordPayload = isPlainObject(modernizationPacketRecord) ? modernizationPacketRecord : {};
3220
+ const resolvedModernizationPacketId = cleanText(packetRecordPayload.modernization_packet_id)
3221
+ || cleanText(packetRecordPayload.modernizationPacketId)
3222
+ || cleanText(packetRecordPayload.work_packet_id)
3223
+ || cleanText(packetRecordPayload.workPacketId)
3224
+ || normalizedModernizationPacketId
3225
+ || null;
3226
+ const resolvedImplementationItemId = cleanText(packetRecordPayload.implementation_item_id)
3227
+ || cleanText(packetRecordPayload.implementationItemId)
3228
+ || cleanText(packetRecordPayload.roadmap_item_id)
3229
+ || cleanText(packetRecordPayload.roadmapItemId)
3230
+ || cleanText(implementation_item_id)
3231
+ || cleanText(implementationItemId)
3232
+ || null;
3233
+
3234
+ const acceptanceCriteriaResolved = normalizedAcceptanceCriteria.length > 0
3235
+ ? normalizedAcceptanceCriteria
3236
+ : cleanList(packetRecordPayload.acceptance_criteria || packetRecordPayload.acceptanceCriteria || []);
3237
+ const evidenceRefs = cleanList([
3238
+ ...(Array.isArray(wrapperEvidencePayload.evidence_refs) ? wrapperEvidencePayload.evidence_refs : []),
3239
+ ...(Array.isArray(wrapperEvidencePayload.evidenceRefs) ? wrapperEvidencePayload.evidenceRefs : []),
3240
+ ]);
3241
+ const requiredEvidenceMissing = normalizedRequiredEvidence.filter((evidenceRef) => !evidenceRefs.includes(evidenceRef));
3242
+ const evidenceStatus = wrapperEvidencePayload.wrapper_execution_record
3243
+ ? (wrapperEvidencePayload.gate_ready === true ? 'complete' : 'incomplete')
3244
+ : 'absent';
3245
+ const verificationStatus = cleanText(wrapperEvidencePayload.verification_status)
3246
+ || cleanText(wrapperEvidencePayload.wrapper_verification_summary?.verification_status)
3247
+ || cleanText(wrapperEvidencePayload.wrapper_verification_summary?.verificationStatus)
3248
+ || null;
3249
+ const evidenceComplete = evidenceStatus === 'complete' && verificationStatus === 'pass' && requiredEvidenceMissing.length === 0;
3250
+ const reviewChannelPresent = Boolean(normalizedReviewChannelId);
3251
+ const reviewRequiredResolved = Boolean(normalizedReviewRequired || evidenceStatus !== 'complete' || verificationStatus !== 'pass' || requiredEvidenceMissing.length > 0 || acceptanceCriteriaResolved.length === 0);
3252
+ const recommendedDecision = evidenceComplete ? 'pass' : (reviewRequiredResolved ? 'pending' : 'block');
3253
+ const gateDecisionRequested = normalizedRecordDecision && evidenceComplete;
3254
+
3255
+ let gateDecisionResult = null;
3256
+ const gateDecisionSurface = typeof client.createImplementationPacketGateDecision === 'function'
3257
+ ? client.createImplementationPacketGateDecision.bind(client)
3258
+ : null;
3259
+ if (normalizedRecordDecision && !gateDecisionSurface) {
3260
+ missingSurfaces.push('createImplementationPacketGateDecision');
3261
+ }
3262
+ if (normalizedRecordDecision && gateDecisionSurface) {
3263
+ gateDecisionResult = await gateDecisionSurface(resolvedModernizationPacketId, {
3264
+ gate_type: cleanText(normalizedDecisionBand) || 'modernization_gate',
3265
+ decision: evidenceComplete ? 'pass' : 'block',
3266
+ rationale: normalizedRationale
3267
+ || (evidenceComplete
3268
+ ? 'Wrapper evidence satisfies the modernization gate.'
3269
+ : 'Wrapper evidence is incomplete or unavailable; the gate cannot be marked as pass.'),
3270
+ evidence_refs: evidenceRefs,
3271
+ remediation_actions: evidenceComplete ? [] : ['Review wrapper evidence and missing modernization surfaces.'],
3272
+ decided_by: normalizedReviewer || normalizedSubmittedBy || client.agentSessionId || client.actorId || null,
3273
+ }).catch(() => null);
3274
+ }
3275
+
3276
+ let gateDecisionId = cleanText(gateDecisionResult?.implementation_gate_decision_id)
3277
+ || cleanText(gateDecisionResult?.gate_decision_id)
3278
+ || null;
3279
+
3280
+ let evidenceLinkResult = null;
3281
+ if (gateDecisionId && typeof client.addImplementationItemEvidence === 'function' && resolvedImplementationItemId) {
3282
+ evidenceLinkResult = await client.addImplementationItemEvidence(
3283
+ resolvedImplementationItemId,
3284
+ {
3285
+ evidence_type: 'modernization_gate_decision',
3286
+ evidence_ref: gateDecisionId,
3287
+ title: `Modernization gate decision for ${resolvedModernizationPacketId}`,
3288
+ recorded_by: normalizedReviewer || normalizedSubmittedBy || client.agentSessionId || client.actorId || null,
3289
+ metadata: {
3290
+ ...normalizedMetadata,
3291
+ source: 'decideModernizationGate',
3292
+ modernization_packet_id: resolvedModernizationPacketId,
3293
+ wrapper_execution_id: cleanText(wrapperEvidencePayload.wrapper_execution_id) || cleanText(wrapperEvidencePayload.wrapper_execution_record?.execution_id) || null,
3294
+ decision: gateDecisionResult?.decision || (evidenceComplete ? 'pass' : 'block'),
3295
+ },
3296
+ },
3297
+ ).catch(() => null);
3298
+ } else if (gateDecisionId && !resolvedImplementationItemId) {
3299
+ missingSurfaces.push('addImplementationItemEvidence');
3300
+ }
3301
+
3302
+ let watchResult = null;
3303
+ if (reviewRequiredResolved && reviewChannelPresent) {
3304
+ const watchSurface = typeof client.startMessageWatch === 'function'
3305
+ ? client.startMessageWatch.bind(client)
3306
+ : null;
3307
+ if (!watchSurface) {
3308
+ missingSurfaces.push('startMessageWatch');
3309
+ } else {
3310
+ watchResult = await watchSurface({
3311
+ transferChannelId: normalizedReviewChannelId,
3312
+ workTransferPacketId: cleanText(wrapperEvidencePayload.transfer_packet_id) || cleanText(wrapperEvidencePayload.modernization_packet_id) || resolvedModernizationPacketId,
3313
+ workflowRunId: resolvedWorkflowRunId,
3314
+ watchingAgentRole: normalizedSubmittedBy,
3315
+ expectedFromRole: normalizedReviewer || 'reviewer',
3316
+ expectedMessageKind: 'response',
3317
+ watchType: 'expected_peer_message',
3318
+ watchingAgentSessionId: normalizedSubmittedBy,
3319
+ expectedPayload: {
3320
+ modernization_packet_id: resolvedModernizationPacketId,
3321
+ expected_decision: recommendedDecision,
3322
+ },
3323
+ currentStatus: 'watching',
3324
+ operatorNudge: normalizedRationale || 'Review modernization gate recommendation.',
3325
+ metadata: {
3326
+ ...normalizedMetadata,
3327
+ source: 'decideModernizationGate',
3328
+ },
3329
+ }).catch(() => null);
3330
+ }
3331
+ }
3332
+
3333
+ const watchPayload = isPlainObject(watchResult) ? watchResult : {};
3334
+ const watchId = cleanText(watchPayload.message_watch_id)
3335
+ || cleanText(watchPayload.watch_id)
3336
+ || cleanText(watchPayload.message_watch?.message_watch_id)
3337
+ || cleanText(watchPayload.message_watch?.watch_id)
3338
+ || null;
3339
+
3340
+ let heartbeatResult = null;
3341
+ if (reviewChannelPresent && typeof client.postCollaborationHeartbeat === 'function') {
3342
+ heartbeatResult = await client.postCollaborationHeartbeat({
3343
+ transferChannelId: normalizedReviewChannelId,
3344
+ workTransferPacketId: cleanText(wrapperEvidencePayload.transfer_packet_id) || resolvedModernizationPacketId,
3345
+ workflowRunId: resolvedWorkflowRunId,
3346
+ participantRole: normalizedReviewer ? 'reviewer' : 'gate_reviewer',
3347
+ currentPhase: 'modernization_gate_review',
3348
+ currentTaskSummary: normalizedRationale || `Review modernization gate for ${resolvedModernizationPacketId}`,
3349
+ metadata: {
3350
+ ...normalizedMetadata,
3351
+ source: 'decideModernizationGate',
3352
+ },
3353
+ }).catch(() => null);
3354
+ } else if (reviewChannelPresent) {
3355
+ missingSurfaces.push('postCollaborationHeartbeat');
3356
+ }
3357
+ const heartbeatPayload = isPlainObject(heartbeatResult) ? heartbeatResult : {};
3358
+ const heartbeatStatus = cleanText(heartbeatPayload.collaboration_heartbeat?.activity_state)
3359
+ || cleanText(heartbeatPayload.activity_state)
3360
+ || cleanText(heartbeatPayload.status)
3361
+ || null;
3362
+
3363
+ const projectRoadmapSummary = resolvedProjectId && typeof client.getProjectRoadmapSummary === 'function'
3364
+ ? await client.getProjectRoadmapSummary(resolvedProjectId).catch(() => null)
3365
+ : null;
3366
+ const projectActiveItem = resolvedProjectId && typeof client.getProjectRoadmapActiveItem === 'function'
3367
+ ? await client.getProjectRoadmapActiveItem(resolvedProjectId).catch(() => null)
3368
+ : null;
3369
+ let projectProjection = null;
3370
+ if (include_projection ?? includeProjection ?? true) {
3371
+ const projectProjectionSurface = typeof client.getLogaProjectPortfolioProjection === 'function'
3372
+ ? client.getLogaProjectPortfolioProjection.bind(client)
3373
+ : null;
3374
+ if (projectProjectionSurface) {
3375
+ projectProjection = await projectProjectionSurface().catch(() => null);
3376
+ } else {
3377
+ missingSurfaces.push('getLogaProjectPortfolioProjection');
3378
+ }
3379
+ }
3380
+
3381
+ const operatorProjectionMetadata = {
3382
+ modernization_packet_record: modernizationPacketRecord,
3383
+ wrapper_evidence: wrapperEvidencePayload,
3384
+ gate_decision: gateDecisionResult,
3385
+ gate_decision_evidence_link: evidenceLinkResult,
3386
+ project_roadmap_summary: projectRoadmapSummary,
3387
+ project_roadmap_active_item: projectActiveItem,
3388
+ project_projection: projectProjection,
3389
+ review_watch: watchPayload,
3390
+ review_heartbeat: heartbeatPayload,
3391
+ acceptance_criteria: acceptanceCriteriaResolved,
3392
+ };
3393
+
3394
+ const status = evidenceComplete
3395
+ ? (gateDecisionRequested ? 'ready' : (missingSurfaces.length > 0 ? 'partial' : 'ready'))
3396
+ : (reviewRequiredResolved ? 'review_required' : 'blocked');
3397
+
3398
+ return {
3399
+ status,
3400
+ project_id: resolvedProjectId || null,
3401
+ modernization_packet_id: resolvedModernizationPacketId,
3402
+ wrapper_execution_id: cleanText(wrapperEvidencePayload.wrapper_execution_id) || cleanText(wrapperEvidencePayload.wrapper_execution_record?.execution_id) || normalizedWrapperExecutionId || null,
3403
+ evidence_status: evidenceStatus,
3404
+ verification_status: verificationStatus,
3405
+ recommended_decision: recommendedDecision,
3406
+ gate_decision_id: gateDecisionId || null,
3407
+ review_required: reviewRequiredResolved,
3408
+ watch_id: watchId || null,
3409
+ heartbeat_status: heartbeatStatus,
3410
+ operator_projection_metadata: operatorProjectionMetadata,
3411
+ missing_surfaces: [...new Set(missingSurfaces)],
3412
+ project: projectPayload,
3413
+ modernization_packet_record: modernizationPacketRecord,
3414
+ wrapper_evidence: wrapperEvidencePayload,
3415
+ gate_decision: gateDecisionResult,
3416
+ gate_decision_evidence_link: evidenceLinkResult,
3417
+ review_watch: watchPayload,
3418
+ review_heartbeat: heartbeatPayload,
10
3419
  };
11
3420
  }