@pellux/goodvibes-sdk 0.33.23 → 0.33.25

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/dist/contracts/artifacts/operator-contract.json +1 -1
  2. package/dist/events/agents.d.ts +3 -3
  3. package/dist/events/agents.d.ts.map +1 -1
  4. package/dist/events/orchestration.d.ts +1 -1
  5. package/dist/events/orchestration.d.ts.map +1 -1
  6. package/dist/events/workflows.d.ts +1 -1
  7. package/dist/events/workflows.d.ts.map +1 -1
  8. package/dist/platform/agents/archetypes.d.ts.map +1 -1
  9. package/dist/platform/agents/archetypes.js +14 -0
  10. package/dist/platform/agents/communication-policy.d.ts.map +1 -1
  11. package/dist/platform/agents/communication-policy.js +4 -0
  12. package/dist/platform/agents/orchestrator-prompts.d.ts.map +1 -1
  13. package/dist/platform/agents/orchestrator-prompts.js +2 -0
  14. package/dist/platform/agents/wrfc-controller.d.ts +13 -0
  15. package/dist/platform/agents/wrfc-controller.d.ts.map +1 -1
  16. package/dist/platform/agents/wrfc-controller.js +425 -7
  17. package/dist/platform/agents/wrfc-runtime-events.d.ts +1 -1
  18. package/dist/platform/agents/wrfc-runtime-events.d.ts.map +1 -1
  19. package/dist/platform/agents/wrfc-types.d.ts +29 -4
  20. package/dist/platform/agents/wrfc-types.d.ts.map +1 -1
  21. package/dist/platform/agents/wrfc-workmap.d.ts +2 -1
  22. package/dist/platform/agents/wrfc-workmap.d.ts.map +1 -1
  23. package/dist/platform/companion/companion-chat-manager.d.ts +1 -0
  24. package/dist/platform/companion/companion-chat-manager.d.ts.map +1 -1
  25. package/dist/platform/companion/companion-chat-manager.js +48 -1
  26. package/dist/platform/runtime/emitters/agents.d.ts +3 -3
  27. package/dist/platform/runtime/emitters/agents.d.ts.map +1 -1
  28. package/dist/platform/runtime/emitters/orchestration.d.ts +1 -1
  29. package/dist/platform/runtime/emitters/orchestration.d.ts.map +1 -1
  30. package/dist/platform/runtime/store/domains/agents.d.ts +2 -2
  31. package/dist/platform/runtime/store/domains/agents.d.ts.map +1 -1
  32. package/dist/platform/runtime/store/domains/orchestration.d.ts +1 -1
  33. package/dist/platform/runtime/store/domains/orchestration.d.ts.map +1 -1
  34. package/dist/platform/tools/agent/index.d.ts.map +1 -1
  35. package/dist/platform/tools/agent/index.js +2 -0
  36. package/dist/platform/tools/agent/manager.d.ts +2 -0
  37. package/dist/platform/tools/agent/manager.d.ts.map +1 -1
  38. package/dist/platform/tools/agent/manager.js +22 -3
  39. package/dist/platform/tools/agent/schema.d.ts +2 -0
  40. package/dist/platform/tools/agent/schema.d.ts.map +1 -1
  41. package/dist/platform/tools/agent/schema.js +4 -4
  42. package/dist/platform/tools/agent/wrfc-batch-policy.d.ts +1 -0
  43. package/dist/platform/tools/agent/wrfc-batch-policy.d.ts.map +1 -1
  44. package/dist/platform/tools/agent/wrfc-batch-policy.js +95 -1
  45. package/dist/platform/version.js +1 -1
  46. package/package.json +9 -9
@@ -16,7 +16,8 @@ import { runWrfcGateChecks } from './wrfc-gate-runtime.js';
16
16
  export { extractScoreFromText, extractPassedFromText, extractIssuesFromText } from './wrfc-reporting.js';
17
17
  const VALID_TRANSITIONS = {
18
18
  pending: ['engineering'],
19
- engineering: ['reviewing', 'failed'],
19
+ engineering: ['integrating', 'reviewing', 'failed'],
20
+ integrating: ['reviewing', 'failed'],
20
21
  reviewing: ['fixing', 'awaiting_gates', 'failed'],
21
22
  fixing: ['reviewing', 'failed'],
22
23
  awaiting_gates: ['gating', 'failed'],
@@ -149,10 +150,13 @@ export class WrfcController {
149
150
  emitWrfcStateChanged(this.runtimeBus, this.sessionId, chain.id, from, to);
150
151
  logger.debug('WrfcController.transition', { chainId: chain.id, from, to });
151
152
  }
152
- applyWrfcAgentMetadata(chain, record, role) {
153
+ applyWrfcAgentMetadata(chain, record, role, subtaskId) {
153
154
  record.wrfcId = chain.id;
154
155
  record.wrfcRole = role;
155
156
  record.wrfcPhaseOrder = this.wrfcPhaseOrder(role);
157
+ if (subtaskId) {
158
+ record.wrfcSubtaskId = subtaskId;
159
+ }
156
160
  if (role === 'owner') {
157
161
  record.progress = this.ownerProgress(chain);
158
162
  }
@@ -207,20 +211,28 @@ export class WrfcController {
207
211
  });
208
212
  }
209
213
  ownerProgress(chain) {
214
+ if (chain.subtasks && chain.subtasks.length > 0) {
215
+ const passed = chain.subtasks.filter((subtask) => subtask.state === 'passed').length;
216
+ return `WRFC owner supervising compound chain (${chain.state}, ${passed}/${chain.subtasks.length} deliverables passed)`;
217
+ }
210
218
  return `WRFC owner supervising child agents (${chain.state})`;
211
219
  }
212
220
  wrfcPhaseOrder(role) {
213
221
  switch (role) {
214
222
  case 'owner':
215
223
  return 0;
224
+ case 'orchestrator':
225
+ return 0;
216
226
  case 'engineer':
217
227
  return 1;
218
228
  case 'reviewer':
219
229
  return 2;
220
230
  case 'fixer':
221
231
  return 3;
222
- case 'verifier':
232
+ case 'integrator':
223
233
  return 4;
234
+ case 'verifier':
235
+ return 5;
224
236
  }
225
237
  }
226
238
  setupListeners() {
@@ -264,6 +276,23 @@ export class WrfcController {
264
276
  state: chain.state,
265
277
  outputLength: rawOutput.length,
266
278
  });
279
+ const subtask = this.findSubtaskByAgentId(chain, agentId);
280
+ if (subtask) {
281
+ await this.onCompoundSubtaskAgentComplete(chain, subtask, agentId, rawOutput, record ?? undefined);
282
+ if (this.planManager) {
283
+ completePlanItemsForAgent(agentId, this.planManager);
284
+ }
285
+ return;
286
+ }
287
+ if (agentId === chain.integratorAgentId) {
288
+ const report = parseEngineerCompletionReport(rawOutput, record?.template);
289
+ this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
290
+ this.handleIntegratorCompletion(chain, agentId, report);
291
+ if (this.planManager) {
292
+ completePlanItemsForAgent(agentId, this.planManager);
293
+ }
294
+ return;
295
+ }
267
296
  if (chain.state === 'pending') {
268
297
  chain.bufferedCompletion = { agentId, fullOutput: rawOutput };
269
298
  logger.debug('WrfcController.onAgentComplete: chain pending, buffering completion', {
@@ -541,6 +570,47 @@ export class WrfcController {
541
570
  constraintFailure: unsatisfiedConstraintIds.length > 0,
542
571
  };
543
572
  }
573
+ evaluateSubtaskConstraints(subtask, review) {
574
+ if (subtask.constraints.length === 0) {
575
+ return {
576
+ constraintsSatisfied: 0,
577
+ constraintsTotal: 0,
578
+ unsatisfiedConstraintIds: [],
579
+ ignoredConstraintFindingIds: [],
580
+ constraintFailure: false,
581
+ };
582
+ }
583
+ const expectedIds = new Set(subtask.constraints.map((constraint) => constraint.id));
584
+ const findingMap = new Map();
585
+ const ignoredConstraintFindingIds = [];
586
+ for (const finding of review.constraintFindings ?? []) {
587
+ if (!expectedIds.has(finding.constraintId)) {
588
+ ignoredConstraintFindingIds.push(finding.constraintId);
589
+ continue;
590
+ }
591
+ if (!findingMap.has(finding.constraintId)) {
592
+ findingMap.set(finding.constraintId, finding);
593
+ }
594
+ }
595
+ let constraintsSatisfied = 0;
596
+ const unsatisfiedConstraintIds = [];
597
+ for (const constraint of subtask.constraints) {
598
+ const finding = findingMap.get(constraint.id);
599
+ if (finding?.satisfied === true) {
600
+ constraintsSatisfied += 1;
601
+ }
602
+ else {
603
+ unsatisfiedConstraintIds.push(constraint.id);
604
+ }
605
+ }
606
+ return {
607
+ constraintsSatisfied,
608
+ constraintsTotal: subtask.constraints.length,
609
+ unsatisfiedConstraintIds,
610
+ ignoredConstraintFindingIds,
611
+ constraintFailure: unsatisfiedConstraintIds.length > 0,
612
+ };
613
+ }
544
614
  async processGateResults(chain, results) {
545
615
  if (!chain.currentNodeId?.includes(':gate:')) {
546
616
  chain.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `gate:${chain.reviewCycles}:${chain.fixAttempts}`, 'verifier', 'Quality gates');
@@ -635,6 +705,7 @@ export class WrfcController {
635
705
  const allChains = Array.from(this.chains.values()).filter((chain) => chain.state !== 'passed' && chain.state !== 'failed');
636
706
  const activeWorkChains = allChains.filter((chain) => (chain.state === 'pending'
637
707
  || chain.state === 'engineering'
708
+ || chain.state === 'integrating'
638
709
  || chain.state === 'reviewing'
639
710
  || chain.state === 'fixing'));
640
711
  if (activeWorkChains.length > 0) {
@@ -703,6 +774,12 @@ export class WrfcController {
703
774
  }
704
775
  const wasActive = chain.state !== 'passed' && chain.state !== 'failed' && chain.state !== 'pending';
705
776
  this.failCurrentNode(chain, reason);
777
+ for (const subtask of chain.subtasks ?? []) {
778
+ if (subtask.currentNodeId) {
779
+ failWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, subtask.currentNodeId, reason);
780
+ subtask.currentNodeId = undefined;
781
+ }
782
+ }
706
783
  try {
707
784
  this.transition(chain, 'failed');
708
785
  }
@@ -854,7 +931,26 @@ export class WrfcController {
854
931
  failWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, chain.currentNodeId, error);
855
932
  chain.currentNodeId = undefined;
856
933
  }
934
+ completeSubtaskNode(chain, subtask, summary) {
935
+ if (!subtask.currentNodeId)
936
+ return;
937
+ completeWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, subtask.currentNodeId, summary);
938
+ subtask.currentNodeId = undefined;
939
+ }
857
940
  createBaseChain(ownerRecord) {
941
+ const subtasks = (ownerRecord.wrfcSubtasks ?? [])
942
+ .filter((task) => typeof task.task === 'string' && task.task.trim().length > 0)
943
+ .map((task, index) => ({
944
+ id: `deliverable-${index + 1}`,
945
+ title: task.task.trim().slice(0, 80),
946
+ task: task.task.trim(),
947
+ state: 'pending',
948
+ fixAttempts: 0,
949
+ reviewCycles: 0,
950
+ reviewScores: [],
951
+ constraints: [],
952
+ constraintsEnumerated: false,
953
+ }));
858
954
  const chain = {
859
955
  id: this.generateWrfcId(),
860
956
  state: 'pending',
@@ -869,6 +965,7 @@ export class WrfcController {
869
965
  constraints: [],
870
966
  constraintsEnumerated: false,
871
967
  createdAt: Date.now(),
968
+ ...(subtasks.length > 1 ? { subtasks } : {}),
872
969
  };
873
970
  this.chains.set(chain.id, chain);
874
971
  emitWrfcGraphCreated(this.runtimeBus, this.sessionId, chain.id, `WRFC: ${ownerRecord.task}`);
@@ -886,6 +983,10 @@ export class WrfcController {
886
983
  return chain;
887
984
  }
888
985
  startEngineeringChain(chain, emitCreated) {
986
+ if (chain.subtasks && chain.subtasks.length > 1) {
987
+ this.startCompoundEngineeringChain(chain, emitCreated);
988
+ return;
989
+ }
889
990
  this.activeChainCount += 1;
890
991
  this.transition(chain, 'engineering');
891
992
  this.setWrfcWorkPlanTaskStatus(chain, chain.ownerAgentId, 'in_progress');
@@ -909,6 +1010,34 @@ export class WrfcController {
909
1010
  });
910
1011
  this.upsertWrfcWorkPlanTask(chain, 'engineer', engineerRecord, 'in_progress');
911
1012
  }
1013
+ startCompoundEngineeringChain(chain, emitCreated) {
1014
+ this.activeChainCount += 1;
1015
+ this.transition(chain, 'engineering');
1016
+ this.setWrfcWorkPlanTaskStatus(chain, chain.ownerAgentId, 'in_progress');
1017
+ if (emitCreated) {
1018
+ emitWrfcChainCreated(this.runtimeBus, this.sessionId, chain.id, chain.task);
1019
+ }
1020
+ this.appendOwnerDecision(chain, 'compound_started', `Compound WRFC owner supervising ${chain.subtasks?.length ?? 0} deliverables under one chain`, { agentId: chain.ownerAgentId });
1021
+ for (const subtask of chain.subtasks ?? []) {
1022
+ subtask.state = 'engineering';
1023
+ const engineerRecord = this.spawnWrfcAgent(chain, 'engineer', 'engineer', this.buildSubtaskEngineerTask(chain, subtask), true, subtask.id);
1024
+ this.applyWrfcAgentMetadata(chain, engineerRecord, 'engineer', subtask.id);
1025
+ subtask.engineerAgentId = engineerRecord.id;
1026
+ chain.allAgentIds.push(engineerRecord.id);
1027
+ this.messageBus.registerAgent({
1028
+ agentId: engineerRecord.id,
1029
+ role: 'engineer',
1030
+ wrfcId: chain.id,
1031
+ });
1032
+ subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:engineer:0`, 'engineer', `Engineer ${subtask.title}`, engineerRecord.id);
1033
+ this.appendOwnerDecision(chain, 'spawn_engineer', this.withRouteReason(`Start compound WRFC engineer child for ${subtask.id}`, engineerRecord), {
1034
+ agentId: engineerRecord.id,
1035
+ role: 'engineer',
1036
+ record: engineerRecord,
1037
+ });
1038
+ this.upsertWrfcWorkPlanTask(chain, 'engineer', engineerRecord, 'in_progress', subtask.id);
1039
+ }
1040
+ }
912
1041
  handleEngineerCompletion(chain, agentId, report) {
913
1042
  let reportForReview = report;
914
1043
  this.completeCurrentNode(chain, report.summary);
@@ -981,6 +1110,278 @@ export class WrfcController {
981
1110
  }
982
1111
  this.startReview(chain, reportForReview);
983
1112
  }
1113
+ buildSubtaskEngineerTask(chain, subtask) {
1114
+ return [
1115
+ `Compound WRFC engineer task`,
1116
+ `Parent WRFC ask (authoritative whole):`,
1117
+ chain.task,
1118
+ ``,
1119
+ `Sub-deliverable ${subtask.id}:`,
1120
+ subtask.task,
1121
+ ``,
1122
+ `Instructions:`,
1123
+ `1. Implement only this sub-deliverable, but keep the parent ask in mind for compatibility.`,
1124
+ `2. Do not review or verify sibling deliverables. The WRFC owner controls review/fix phases after your output exists.`,
1125
+ `3. Return a structured EngineerReport JSON block.`,
1126
+ ].join('\n');
1127
+ }
1128
+ buildCompoundIntegrationTask(chain) {
1129
+ const subtaskSummaries = (chain.subtasks ?? []).map((subtask) => [
1130
+ `## ${subtask.id}: ${subtask.title}`,
1131
+ `Task: ${subtask.task}`,
1132
+ `Review cycles: ${subtask.reviewCycles}`,
1133
+ `Last score: ${subtask.reviewScores.at(-1) ?? 'n/a'}`,
1134
+ `Engineer summary: ${subtask.engineerReport?.summary ?? '(no summary)'}`,
1135
+ `Reviewer summary: ${subtask.reviewerReport?.summary ?? '(no review)'}`,
1136
+ ].join('\n')).join('\n\n');
1137
+ return [
1138
+ `Compound WRFC integration task`,
1139
+ `Parent WRFC ask (authoritative full scope):`,
1140
+ chain.task,
1141
+ ``,
1142
+ `All sub-deliverables have individually passed review. Integrate them into one coherent final result.`,
1143
+ ``,
1144
+ subtaskSummaries,
1145
+ ``,
1146
+ `Instructions:`,
1147
+ `1. Inspect the current workspace and the sub-deliverable outputs before editing.`,
1148
+ `2. Resolve cross-deliverable API, export, documentation, and test consistency issues.`,
1149
+ `3. Preserve all accepted sub-deliverable behavior; do not start unrelated new work.`,
1150
+ `4. Return a structured EngineerReport JSON block so the final reviewer can inspect integration changes.`,
1151
+ ].join('\n');
1152
+ }
1153
+ findSubtaskByAgentId(chain, agentId) {
1154
+ for (const subtask of chain.subtasks ?? []) {
1155
+ if (subtask.engineerAgentId === agentId
1156
+ || subtask.reviewerAgentId === agentId
1157
+ || subtask.fixerAgentId === agentId) {
1158
+ return subtask;
1159
+ }
1160
+ }
1161
+ return null;
1162
+ }
1163
+ async onCompoundSubtaskAgentComplete(chain, subtask, agentId, rawOutput, record) {
1164
+ if (agentId === subtask.engineerAgentId || agentId === subtask.fixerAgentId) {
1165
+ const report = parseEngineerCompletionReport(rawOutput, record?.template);
1166
+ this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
1167
+ this.handleCompoundEngineerCompletion(chain, subtask, agentId, report);
1168
+ return;
1169
+ }
1170
+ if (agentId === subtask.reviewerAgentId) {
1171
+ const review = parseReviewerCompletionReport(chain.id, rawOutput, getWrfcScoreThreshold(this.configManager));
1172
+ subtask.reviewerReport = review;
1173
+ subtask.reviewCycles += 1;
1174
+ this.setWrfcWorkPlanTaskStatus(chain, agentId, 'done');
1175
+ await this.processCompoundSubtaskReview(chain, subtask, review);
1176
+ }
1177
+ }
1178
+ handleCompoundEngineerCompletion(chain, subtask, agentId, report) {
1179
+ let reportForReview = report;
1180
+ this.completeSubtaskNode(chain, subtask, report.summary);
1181
+ if (subtask.state === 'engineering') {
1182
+ subtask.engineerReport = report;
1183
+ this.workmap.append({
1184
+ ts: new Date().toISOString(),
1185
+ wrfcId: chain.id,
1186
+ event: 'engineer_complete',
1187
+ agentId,
1188
+ task: subtask.task,
1189
+ subtaskId: subtask.id,
1190
+ });
1191
+ }
1192
+ const isEngineerReportShape = (r) => r.archetype === 'engineer';
1193
+ if (!subtask.constraintsEnumerated) {
1194
+ subtask.constraints = isEngineerReportShape(report) ? (report.constraints ?? []) : [];
1195
+ subtask.constraintsEnumerated = true;
1196
+ }
1197
+ else if (isEngineerReportShape(report)) {
1198
+ const fixerConstraints = report.constraints ?? [];
1199
+ reportForReview = this.canonicalizeFixerReportConstraints(report, subtask.constraints);
1200
+ if (subtask.constraints.length === 0) {
1201
+ if (fixerConstraints.length > 0) {
1202
+ logger.warn('WrfcController: ignored compound fixer-invented constraints for unconstrained subtask', {
1203
+ chainId: chain.id,
1204
+ subtaskId: subtask.id,
1205
+ extra: fixerConstraints.map((constraint) => constraint.id),
1206
+ });
1207
+ }
1208
+ }
1209
+ else {
1210
+ const expectedIds = new Set(subtask.constraints.map((constraint) => constraint.id));
1211
+ const actualIds = new Set(fixerConstraints.map((constraint) => constraint.id));
1212
+ const missing = [...expectedIds].filter((id) => !actualIds.has(id));
1213
+ const extra = [...actualIds].filter((id) => !expectedIds.has(id));
1214
+ if (missing.length > 0 || extra.length > 0) {
1215
+ const description = `Fixer regressed constraint continuity for ${subtask.id}: missing=[${missing.join(',')}] extra=[${extra.join(',')}]`;
1216
+ logger.warn('WrfcController: compound fixer constraint-continuity violation', {
1217
+ chainId: chain.id,
1218
+ subtaskId: subtask.id,
1219
+ missing,
1220
+ extra,
1221
+ });
1222
+ subtask.syntheticIssues ??= [];
1223
+ subtask.syntheticIssues.push({ severity: 'critical', description });
1224
+ }
1225
+ }
1226
+ }
1227
+ else if (subtask.constraints.length > 0) {
1228
+ const description = `Fixer regressed constraint continuity for ${subtask.id}: missing=[${subtask.constraints.map((constraint) => constraint.id).join(',')}] extra=[]`;
1229
+ logger.warn('WrfcController: compound fixer constraint-continuity violation', {
1230
+ chainId: chain.id,
1231
+ subtaskId: subtask.id,
1232
+ missing: subtask.constraints.map((constraint) => constraint.id),
1233
+ extra: [],
1234
+ });
1235
+ subtask.syntheticIssues ??= [];
1236
+ subtask.syntheticIssues.push({ severity: 'critical', description });
1237
+ }
1238
+ subtask.engineerReport = reportForReview;
1239
+ this.startCompoundSubtaskReview(chain, subtask, reportForReview);
1240
+ }
1241
+ startCompoundSubtaskReview(chain, subtask, report) {
1242
+ subtask.state = 'reviewing';
1243
+ let reviewTask = buildReviewTask(chain.id, `Parent WRFC ask:\n${chain.task}\n\nSub-deliverable ${subtask.id}:\n${subtask.task}`, report, getWrfcScoreThreshold(this.configManager), subtask.constraints);
1244
+ if (subtask.syntheticIssues && subtask.syntheticIssues.length > 0) {
1245
+ const syntheticBlock = [
1246
+ `## Synthetic issues from controller`,
1247
+ ``,
1248
+ ...subtask.syntheticIssues.map((issue) => `- [${issue.severity.toUpperCase()}] ${issue.description}`),
1249
+ ].join('\n');
1250
+ reviewTask = syntheticBlock + '\n\n---\n\n' + reviewTask;
1251
+ subtask.syntheticIssues = [];
1252
+ }
1253
+ const reviewerRecord = this.spawnWrfcAgent(chain, 'reviewer', 'reviewer', reviewTask, true, subtask.id);
1254
+ subtask.reviewerAgentId = reviewerRecord.id;
1255
+ this.applyWrfcAgentMetadata(chain, reviewerRecord, 'reviewer', subtask.id);
1256
+ chain.allAgentIds.push(reviewerRecord.id);
1257
+ this.messageBus.registerAgent({
1258
+ agentId: reviewerRecord.id,
1259
+ role: 'reviewer',
1260
+ wrfcId: chain.id,
1261
+ });
1262
+ subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:review:${subtask.reviewCycles + 1}`, 'reviewer', `Review ${subtask.title}`, reviewerRecord.id);
1263
+ this.appendOwnerDecision(chain, 'spawn_reviewer', this.withRouteReason(`Review compound sub-deliverable ${subtask.id} after engineer output exists`, reviewerRecord), {
1264
+ agentId: reviewerRecord.id,
1265
+ role: 'reviewer',
1266
+ record: reviewerRecord,
1267
+ });
1268
+ this.upsertWrfcWorkPlanTask(chain, 'reviewer', reviewerRecord, 'in_progress', subtask.id);
1269
+ }
1270
+ async processCompoundSubtaskReview(chain, subtask, review) {
1271
+ const threshold = getWrfcScoreThreshold(this.configManager);
1272
+ const constraintEvaluation = this.evaluateSubtaskConstraints(subtask, review);
1273
+ const passed = review.score >= threshold && !constraintEvaluation.constraintFailure;
1274
+ this.completeSubtaskNode(chain, subtask, `Score ${review.score}/10${passed ? ' passed' : ' needs fixes'}`);
1275
+ emitWorkflowReviewCompleted(this.runtimeBus, createWrfcWorkflowContext(this.sessionId, chain.id), {
1276
+ chainId: chain.id,
1277
+ score: review.score,
1278
+ passed,
1279
+ ...(subtask.constraints.length > 0
1280
+ ? {
1281
+ constraintsSatisfied: constraintEvaluation.constraintsSatisfied,
1282
+ constraintsTotal: constraintEvaluation.constraintsTotal,
1283
+ unsatisfiedConstraintIds: constraintEvaluation.unsatisfiedConstraintIds,
1284
+ }
1285
+ : {}),
1286
+ });
1287
+ this.workmap.append({
1288
+ ts: new Date().toISOString(),
1289
+ wrfcId: chain.id,
1290
+ event: 'review_complete',
1291
+ agentId: subtask.reviewerAgentId,
1292
+ score: review.score,
1293
+ passed,
1294
+ subtaskId: subtask.id,
1295
+ issues: review.issues?.slice(0, 10).map((issue) => ({
1296
+ severity: issue.severity,
1297
+ description: issue.description,
1298
+ file: issue.file,
1299
+ })),
1300
+ });
1301
+ subtask.reviewScores.push(review.score);
1302
+ if (passed) {
1303
+ subtask.state = 'passed';
1304
+ this.appendOwnerDecision(chain, 'subtask_review_passed', `Sub-deliverable ${subtask.id} passed review with ${review.score}/10`, {
1305
+ agentId: subtask.reviewerAgentId,
1306
+ role: 'reviewer',
1307
+ reviewScore: review.score,
1308
+ });
1309
+ if ((chain.subtasks ?? []).every((candidate) => candidate.state === 'passed')) {
1310
+ this.startIntegration(chain);
1311
+ }
1312
+ return;
1313
+ }
1314
+ const maxFixAttempts = getWrfcMaxFixAttempts(this.configManager);
1315
+ if (subtask.fixAttempts >= maxFixAttempts) {
1316
+ subtask.state = 'failed';
1317
+ this.failChain(chain, `Sub-deliverable ${subtask.id} review score ${review.score}/10 below threshold ${threshold}/10 after ${subtask.fixAttempts} fix attempt${subtask.fixAttempts !== 1 ? 's' : ''}`);
1318
+ return;
1319
+ }
1320
+ this.appendOwnerDecision(chain, 'subtask_review_failed', `Sub-deliverable ${subtask.id} review did not pass`, {
1321
+ agentId: subtask.reviewerAgentId,
1322
+ role: 'reviewer',
1323
+ reviewScore: review.score,
1324
+ });
1325
+ this.startCompoundSubtaskFix(chain, subtask, review);
1326
+ }
1327
+ startCompoundSubtaskFix(chain, subtask, review) {
1328
+ subtask.fixAttempts += 1;
1329
+ subtask.state = 'fixing';
1330
+ const targetConstraintIds = this.evaluateSubtaskConstraints(subtask, review).unsatisfiedConstraintIds;
1331
+ emitWorkflowFixAttempted(this.runtimeBus, createWrfcWorkflowContext(this.sessionId, chain.id), {
1332
+ chainId: chain.id,
1333
+ attempt: subtask.fixAttempts,
1334
+ maxAttempts: getWrfcMaxFixAttempts(this.configManager),
1335
+ ...(targetConstraintIds.length > 0 ? { targetConstraintIds } : {}),
1336
+ });
1337
+ const fixerRecord = this.spawnWrfcAgent(chain, 'fixer', 'engineer', buildFixTask(chain.id, `Parent WRFC ask:\n${chain.task}\n\nSub-deliverable ${subtask.id}:\n${subtask.task}`, review, getWrfcScoreThreshold(this.configManager), subtask.fixAttempts, subtask.constraints, review.constraintFindings ?? []), true, subtask.id);
1338
+ subtask.fixerAgentId = fixerRecord.id;
1339
+ this.applyWrfcAgentMetadata(chain, fixerRecord, 'fixer', subtask.id);
1340
+ chain.allAgentIds.push(fixerRecord.id);
1341
+ this.messageBus.registerAgent({
1342
+ agentId: fixerRecord.id,
1343
+ role: 'fixer',
1344
+ wrfcId: chain.id,
1345
+ });
1346
+ subtask.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `subtask:${subtask.id}:fix:${subtask.fixAttempts}`, 'fixer', `Fix ${subtask.title}`, fixerRecord.id);
1347
+ this.appendOwnerDecision(chain, 'spawn_fixer', this.withRouteReason(`Fix compound sub-deliverable ${subtask.id}`, fixerRecord), {
1348
+ agentId: fixerRecord.id,
1349
+ role: 'fixer',
1350
+ record: fixerRecord,
1351
+ });
1352
+ this.upsertWrfcWorkPlanTask(chain, 'fixer', fixerRecord, 'in_progress', subtask.id);
1353
+ }
1354
+ startIntegration(chain) {
1355
+ this.transition(chain, 'integrating');
1356
+ const integratorRecord = this.spawnWrfcAgent(chain, 'integrator', 'integrator', this.buildCompoundIntegrationTask(chain), true);
1357
+ chain.integratorAgentId = integratorRecord.id;
1358
+ this.applyWrfcAgentMetadata(chain, integratorRecord, 'integrator');
1359
+ chain.allAgentIds.push(integratorRecord.id);
1360
+ this.messageBus.registerAgent({
1361
+ agentId: integratorRecord.id,
1362
+ role: 'integrator',
1363
+ wrfcId: chain.id,
1364
+ });
1365
+ chain.currentNodeId = startWrfcOrchestrationNode(this.runtimeBus, this.sessionId, chain.id, `integrator:${Date.now()}`, 'integrator', 'Integrate passed deliverables', integratorRecord.id);
1366
+ this.appendOwnerDecision(chain, 'spawn_integrator', this.withRouteReason('Integrate all passed compound WRFC deliverables before final full-scope review', integratorRecord), {
1367
+ agentId: integratorRecord.id,
1368
+ role: 'integrator',
1369
+ record: integratorRecord,
1370
+ });
1371
+ this.upsertWrfcWorkPlanTask(chain, 'integrator', integratorRecord, 'in_progress');
1372
+ }
1373
+ handleIntegratorCompletion(chain, agentId, report) {
1374
+ chain.integratorReport = report;
1375
+ this.completeCurrentNode(chain, report.summary);
1376
+ this.workmap.append({
1377
+ ts: new Date().toISOString(),
1378
+ wrfcId: chain.id,
1379
+ event: 'integrator_complete',
1380
+ agentId,
1381
+ task: chain.task,
1382
+ });
1383
+ this.startReview(chain, report);
1384
+ }
984
1385
  canonicalizeFixerReportConstraints(report, constraints) {
985
1386
  const canonical = {
986
1387
  ...report,
@@ -997,7 +1398,7 @@ export class WrfcController {
997
1398
  ].join('\n');
998
1399
  return canonical;
999
1400
  }
1000
- spawnWrfcAgent(chain, role, template, task, dangerouslyDisableWrfc) {
1401
+ spawnWrfcAgent(chain, role, template, task, dangerouslyDisableWrfc, subtaskId) {
1001
1402
  const owner = this.agentManager.getStatus(chain.ownerAgentId);
1002
1403
  const selectedRoute = this.selectChildRoute?.({ chain, role, task, ownerAgent: owner }) ?? null;
1003
1404
  const model = selectedRoute?.model ?? owner?.model;
@@ -1016,9 +1417,13 @@ export class WrfcController {
1016
1417
  ...(routing ? { routing } : {}),
1017
1418
  ...(reasoningEffort ? { reasoningEffort } : {}),
1018
1419
  ...(template === 'engineer' ? { systemPromptAddendum: '\n\n---\n\n' + buildEngineerConstraintAddendum() } : {}),
1420
+ ...(template === 'integrator' ? { systemPromptAddendum: '\n\n---\n\n' + buildEngineerConstraintAddendum() } : {}),
1019
1421
  ...(dangerouslyDisableWrfc ? { dangerously_disable_wrfc: true } : {}),
1020
1422
  });
1021
1423
  record.wrfcId = chain.id;
1424
+ if (subtaskId) {
1425
+ record.wrfcSubtaskId = subtaskId;
1426
+ }
1022
1427
  if (selectedRoute?.reason) {
1023
1428
  record.wrfcRouteReason = selectedRoute.reason;
1024
1429
  }
@@ -1075,16 +1480,18 @@ export class WrfcController {
1075
1480
  });
1076
1481
  }
1077
1482
  }
1078
- upsertWrfcWorkPlanTask(chain, role, record, status) {
1483
+ upsertWrfcWorkPlanTask(chain, role, record, status, subtaskId) {
1079
1484
  if (!this.workPlanService)
1080
1485
  return;
1081
1486
  const taskId = this.workPlanTaskIdForAgent(chain, record.id, role);
1082
1487
  const task = {
1083
1488
  taskId,
1084
- title: this.workPlanTaskTitle(role, chain.task),
1489
+ title: this.workPlanTaskTitle(role, role === 'owner' ? chain.task : record.task),
1085
1490
  notes: role === 'owner'
1086
1491
  ? 'WRFC owner chain supervising lifecycle child agents.'
1087
- : `WRFC ${role} phase for the owner chain.`,
1492
+ : subtaskId
1493
+ ? `WRFC ${role} phase for compound deliverable ${subtaskId}.`
1494
+ : `WRFC ${role} phase for the owner chain.`,
1088
1495
  owner: role,
1089
1496
  status,
1090
1497
  source: 'wrfc',
@@ -1097,6 +1504,7 @@ export class WrfcController {
1097
1504
  metadata: {
1098
1505
  wrfcState: chain.state,
1099
1506
  agentTemplate: record.template,
1507
+ ...(subtaskId ? { wrfcSubtaskId: subtaskId } : {}),
1100
1508
  },
1101
1509
  };
1102
1510
  this.enqueueWrfcWorkPlanTaskOperation(taskId, async () => {
@@ -1177,6 +1585,16 @@ export class WrfcController {
1177
1585
  return 'reviewer';
1178
1586
  if (agentId === chain.fixerAgentId)
1179
1587
  return 'fixer';
1588
+ if (agentId === chain.integratorAgentId)
1589
+ return 'integrator';
1590
+ for (const subtask of chain.subtasks ?? []) {
1591
+ if (agentId === subtask.engineerAgentId)
1592
+ return 'engineer';
1593
+ if (agentId === subtask.reviewerAgentId)
1594
+ return 'reviewer';
1595
+ if (agentId === subtask.fixerAgentId)
1596
+ return 'fixer';
1597
+ }
1180
1598
  return null;
1181
1599
  }
1182
1600
  workPlanTaskIdForAgent(chain, agentId, role) {
@@ -6,7 +6,7 @@ export type WorkflowContext = {
6
6
  traceId: string;
7
7
  source: string;
8
8
  };
9
- export type WrfcNodeRole = 'engineer' | 'reviewer' | 'fixer' | 'verifier';
9
+ export type WrfcNodeRole = 'orchestrator' | 'engineer' | 'reviewer' | 'fixer' | 'integrator' | 'verifier';
10
10
  export declare function createWrfcWorkflowContext(sessionId: string, chainId: string): WorkflowContext;
11
11
  export declare function createWrfcOrchestrationGraphId(chainId: string): string;
12
12
  export declare function emitWrfcStateChanged(runtimeBus: RuntimeEventBus, sessionId: string, chainId: string, from: WrfcState, to: WrfcState): void;
@@ -1 +1 @@
1
- {"version":3,"file":"wrfc-runtime-events.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-runtime-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAgBjD,MAAM,MAAM,eAAe,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrF,MAAM,MAAM,YAAY,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,UAAU,CAAC;AAE1E,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAM7F;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,SAAS,GACZ,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExH;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAEvI;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEzG;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,GAC9B,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,UAAU,EAAE,GACxB,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,IAAI,CAMN;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAqBR;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAUN;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,IAAI,CAUN"}
1
+ {"version":3,"file":"wrfc-runtime-events.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-runtime-events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAgBjD,MAAM,MAAM,eAAe,GAAG;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AACrF,MAAM,MAAM,YAAY,GAAG,cAAc,GAAG,UAAU,GAAG,UAAU,GAAG,OAAO,GAAG,YAAY,GAAG,UAAU,CAAC;AAE1G,wBAAgB,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,eAAe,CAM7F;AAED,wBAAgB,8BAA8B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,EAAE,EAAE,SAAS,GACZ,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAExH;AAED,wBAAgB,kBAAkB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,CAEvI;AAED,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAEzG;AAED,wBAAgB,qBAAqB,CACnC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,GAC9B,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,IAAI,CAEN;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,WAAW,EAAE,UAAU,EAAE,GACxB,IAAI,CAEN;AAED,wBAAgB,oBAAoB,CAClC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,IAAI,CAMN;AAED,wBAAgB,0BAA0B,CACxC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,MAAM,EACb,OAAO,CAAC,EAAE,MAAM,GACf,MAAM,CAqBR;AAED,wBAAgB,6BAA6B,CAC3C,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,GACf,IAAI,CAUN;AAED,wBAAgB,yBAAyB,CACvC,UAAU,EAAE,eAAe,EAC3B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,GACZ,IAAI,CAUN"}
@@ -6,10 +6,11 @@ export interface QueuedChain {
6
6
  queuedAt: number;
7
7
  }
8
8
  /** WRFC chain lifecycle states. */
9
- export type WrfcState = 'pending' | 'engineering' | 'reviewing' | 'fixing' | 'awaiting_gates' | 'gating' | 'passed' | 'failed' | 'committing';
9
+ export type WrfcState = 'pending' | 'engineering' | 'integrating' | 'reviewing' | 'fixing' | 'awaiting_gates' | 'gating' | 'passed' | 'failed' | 'committing';
10
10
  /** Agent role within a WRFC chain. The owner is the durable chain orchestrator. */
11
- export type WrfcAgentRole = 'owner' | 'engineer' | 'reviewer' | 'fixer' | 'verifier';
12
- export type WrfcOwnerDecisionAction = 'chain_created' | 'spawn_engineer' | 'spawn_reviewer' | 'spawn_fixer' | 'spawn_gate_fixer' | 'review_passed' | 'review_failed' | 'gate_passed' | 'gate_failed' | 'chain_passed' | 'chain_failed' | 'chain_cancelled' | 'owner_completion_ignored' | 'owner_failure_ignored' | 'resume_skipped' | 'resume_started';
11
+ export type WrfcAgentRole = 'owner' | 'orchestrator' | 'engineer' | 'reviewer' | 'fixer' | 'integrator' | 'verifier';
12
+ export type WrfcSubtaskState = 'pending' | 'engineering' | 'reviewing' | 'fixing' | 'passed' | 'failed';
13
+ export type WrfcOwnerDecisionAction = 'chain_created' | 'compound_started' | 'spawn_engineer' | 'spawn_reviewer' | 'spawn_fixer' | 'spawn_integrator' | 'spawn_gate_fixer' | 'subtask_review_passed' | 'subtask_review_failed' | 'review_passed' | 'review_failed' | 'gate_passed' | 'gate_failed' | 'chain_passed' | 'chain_failed' | 'chain_cancelled' | 'owner_completion_ignored' | 'owner_failure_ignored' | 'resume_skipped' | 'resume_started';
13
14
  export interface WrfcOwnerDecision {
14
15
  id: string;
15
16
  ts: string;
@@ -33,10 +34,31 @@ export interface WrfcChildRouteSelection {
33
34
  }
34
35
  export type WrfcChildRouteSelector = (context: {
35
36
  readonly chain: WrfcChain;
36
- readonly role: Exclude<WrfcAgentRole, 'owner' | 'verifier'>;
37
+ readonly role: Exclude<WrfcAgentRole, 'owner' | 'orchestrator' | 'verifier'>;
37
38
  readonly task: string;
38
39
  readonly ownerAgent: AgentRecord | null;
39
40
  }) => WrfcChildRouteSelection | null | undefined;
41
+ export interface WrfcSubtask {
42
+ id: string;
43
+ title: string;
44
+ task: string;
45
+ state: WrfcSubtaskState;
46
+ currentNodeId?: string | undefined;
47
+ engineerAgentId?: string | undefined;
48
+ reviewerAgentId?: string | undefined;
49
+ fixerAgentId?: string | undefined;
50
+ engineerReport?: CompletionReport | undefined;
51
+ reviewerReport?: ReviewerReport | undefined;
52
+ fixAttempts: number;
53
+ reviewCycles: number;
54
+ reviewScores: number[];
55
+ constraints: Constraint[];
56
+ constraintsEnumerated: boolean;
57
+ syntheticIssues?: Array<{
58
+ severity: 'critical';
59
+ description: string;
60
+ }> | undefined;
61
+ }
40
62
  /** A single WRFC chain instance. */
41
63
  export interface WrfcChain {
42
64
  id: string;
@@ -47,10 +69,13 @@ export interface WrfcChain {
47
69
  engineerAgentId?: string | undefined;
48
70
  reviewerAgentId?: string | undefined;
49
71
  fixerAgentId?: string | undefined;
72
+ integratorAgentId?: string | undefined;
50
73
  /** All agent IDs involved in this chain (for worktree cleanup). */
51
74
  allAgentIds: string[];
52
75
  engineerReport?: CompletionReport | undefined;
53
76
  reviewerReport?: ReviewerReport | undefined;
77
+ integratorReport?: CompletionReport | undefined;
78
+ subtasks?: WrfcSubtask[] | undefined;
54
79
  fixAttempts: number;
55
80
  reviewCycles: number;
56
81
  gateResults?: QualityGateResult[] | undefined;