@chllming/wave-orchestration 0.8.3 → 0.8.4

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 (39) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/README.md +47 -11
  3. package/docs/README.md +6 -2
  4. package/docs/concepts/what-is-a-wave.md +1 -1
  5. package/docs/plans/architecture-hardening-migration.md +8 -1
  6. package/docs/plans/current-state.md +15 -7
  7. package/docs/plans/end-state-architecture.md +82 -69
  8. package/docs/plans/examples/wave-example-live-proof.md +1 -1
  9. package/docs/plans/migration.md +235 -62
  10. package/docs/plans/wave-orchestrator.md +37 -11
  11. package/docs/reference/cli-reference.md +34 -14
  12. package/docs/reference/coordination-and-closure.md +19 -6
  13. package/docs/reference/npmjs-trusted-publishing.md +5 -4
  14. package/docs/reference/sample-waves.md +4 -4
  15. package/package.json +1 -1
  16. package/releases/manifest.json +20 -0
  17. package/scripts/wave-orchestrator/agent-state.mjs +0 -491
  18. package/scripts/wave-orchestrator/autonomous.mjs +10 -6
  19. package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
  20. package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
  21. package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +395 -139
  22. package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
  23. package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
  24. package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
  25. package/scripts/wave-orchestrator/launcher-runtime.mjs +5 -6
  26. package/scripts/wave-orchestrator/launcher.mjs +271 -724
  27. package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
  28. package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
  29. package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
  30. package/scripts/wave-orchestrator/replay.mjs +3 -1
  31. package/scripts/wave-orchestrator/result-envelope.mjs +589 -0
  32. package/scripts/wave-orchestrator/retry-control.mjs +5 -0
  33. package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +267 -18
  34. package/scripts/wave-orchestrator/role-helpers.mjs +51 -0
  35. package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
  36. package/scripts/wave-orchestrator/shared.mjs +1 -0
  37. package/scripts/wave-orchestrator/traces.mjs +10 -1
  38. package/scripts/wave-orchestrator/wave-files.mjs +11 -9
  39. package/scripts/wave-orchestrator/wave-state-reducer.mjs +52 -5
@@ -5,8 +5,17 @@ import {
5
5
  setWaveDashboardAgent,
6
6
  updateWaveDashboardMessageBoard,
7
7
  } from "./dashboard-state.mjs";
8
+ import {
9
+ materializeAgentExecutionSummaryForRun as materializeAgentExecutionSummaryForRunDefault,
10
+ readWaveComponentMatrixGate as readWaveComponentMatrixGateDefault,
11
+ readWaveContEvalGate as readWaveContEvalGateDefault,
12
+ readWaveContQaGate as readWaveContQaGateDefault,
13
+ readWaveDocumentationGate as readWaveDocumentationGateDefault,
14
+ readWaveIntegrationBarrier as readWaveIntegrationBarrierDefault,
15
+ readWaveSecurityGate as readWaveSecurityGateDefault,
16
+ } from "./gate-engine.mjs";
8
17
  import { REPO_ROOT, toIsoTimestamp } from "./shared.mjs";
9
- import { isSecurityReviewAgent } from "./role-helpers.mjs";
18
+ import { isSecurityReviewAgent, resolveWaveRoleBindings } from "./role-helpers.mjs";
10
19
  import { summarizeResolvedSkills } from "./skills.mjs";
11
20
 
12
21
  function failureResultFromGate(gate, fallbackLogPath) {
@@ -71,76 +80,41 @@ export async function runClosureSweepPhase({
71
80
  materializeAgentExecutionSummaryForRunFn,
72
81
  monitorWaveHumanFeedbackFn,
73
82
  }) {
74
- const contQaAgentId = wave.contQaAgentId || "A0";
75
- const contEvalAgentId = wave.contEvalAgentId || lanePaths.contEvalAgentId || "E0";
76
- const integrationAgentId = wave.integrationAgentId || lanePaths.integrationAgentId || "A8";
77
- const documentationAgentId = wave.documentationAgentId || "A9";
78
- const stagedRuns = [
79
- {
80
- agentId: contEvalAgentId,
81
- label: "cont-EVAL gate",
82
- runs: closureRuns.filter((run) => run.agent.agentId === contEvalAgentId),
83
- validate: () =>
84
- readWaveContEvalGateFn(wave, closureRuns, {
85
- contEvalAgentId,
86
- mode: "live",
87
- evalTargets: wave.evalTargets,
88
- benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
89
- }),
90
- actionRequested:
91
- `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`,
92
- },
93
- {
94
- agentId: "security",
95
- label: "Security review",
96
- runs: closureRuns.filter((run) => isSecurityReviewAgent(run.agent)),
97
- validate: () => readWaveSecurityGateFn(wave, closureRuns),
98
- actionRequested:
99
- `Lane ${lanePaths.lane} owners should resolve blocked security findings or missing approvals before integration closure.`,
100
- },
101
- {
102
- agentId: integrationAgentId,
103
- label: "Integration gate",
104
- runs: closureRuns.filter((run) => run.agent.agentId === integrationAgentId),
105
- validate: () =>
106
- readWaveIntegrationBarrierFn(
107
- wave,
108
- closureRuns,
109
- refreshDerivedState?.(dashboardState?.attempt || 0),
110
- {
111
- integrationAgentId,
112
- requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
113
- },
114
- ),
115
- actionRequested:
116
- `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`,
117
- },
118
- {
119
- agentId: documentationAgentId,
120
- label: "Documentation closure",
121
- runs: closureRuns.filter((run) => run.agent.agentId === documentationAgentId),
122
- validate: () => {
123
- const documentationGate = readWaveDocumentationGateFn(wave, closureRuns);
124
- if (!documentationGate.ok) {
125
- return documentationGate;
126
- }
127
- return readWaveComponentMatrixGateFn(wave, closureRuns, {
128
- laneProfile: lanePaths.laneProfile,
129
- documentationAgentId,
130
- });
131
- },
132
- actionRequested:
133
- `Lane ${lanePaths.lane} owners should resolve the shared-plan or component-matrix closure state before cont-QA progression.`,
134
- },
135
- {
136
- agentId: contQaAgentId,
137
- label: "cont-QA gate",
138
- runs: closureRuns.filter((run) => run.agent.agentId === contQaAgentId),
139
- validate: () => readWaveContQaGateFn(wave, closureRuns, { contQaAgentId, mode: "live" }),
140
- actionRequested:
141
- `Lane ${lanePaths.lane} owners should resolve the cont-QA gate before wave progression.`,
142
- },
143
- ];
83
+ const materializeSummary =
84
+ typeof materializeAgentExecutionSummaryForRunFn === "function"
85
+ ? materializeAgentExecutionSummaryForRunFn
86
+ : materializeAgentExecutionSummaryForRunDefault;
87
+ const monitorHumanFeedback =
88
+ typeof monitorWaveHumanFeedbackFn === "function"
89
+ ? monitorWaveHumanFeedbackFn
90
+ : () => false;
91
+ const readContEvalGate =
92
+ typeof readWaveContEvalGateFn === "function"
93
+ ? readWaveContEvalGateFn
94
+ : readWaveContEvalGateDefault;
95
+ const readSecurityGate =
96
+ typeof readWaveSecurityGateFn === "function"
97
+ ? readWaveSecurityGateFn
98
+ : readWaveSecurityGateDefault;
99
+ const readIntegrationBarrier =
100
+ typeof readWaveIntegrationBarrierFn === "function"
101
+ ? readWaveIntegrationBarrierFn
102
+ : readWaveIntegrationBarrierDefault;
103
+ const readDocumentationGate =
104
+ typeof readWaveDocumentationGateFn === "function"
105
+ ? readWaveDocumentationGateFn
106
+ : readWaveDocumentationGateDefault;
107
+ const readComponentMatrixGate =
108
+ typeof readWaveComponentMatrixGateFn === "function"
109
+ ? readWaveComponentMatrixGateFn
110
+ : readWaveComponentMatrixGateDefault;
111
+ const readContQaGate =
112
+ typeof readWaveContQaGateFn === "function"
113
+ ? readWaveContQaGateFn
114
+ : readWaveContQaGateDefault;
115
+ const stagedRuns = planClosureStages({ lanePaths, wave, closureRuns });
116
+ const { contQaAgentId, contEvalAgentId, integrationAgentId, documentationAgentId } =
117
+ resolveWaveRoleBindings(wave, lanePaths);
144
118
  for (const stage of stagedRuns) {
145
119
  if (stage.runs.length === 0) {
146
120
  continue;
@@ -177,6 +151,11 @@ export async function runClosureSweepPhase({
177
151
  agentRateLimitBaseDelaySeconds: options.agentRateLimitBaseDelaySeconds,
178
152
  agentRateLimitMaxDelaySeconds: options.agentRateLimitMaxDelaySeconds,
179
153
  context7Enabled: options.context7Enabled,
154
+ attempt: dashboardState?.attempt || 1,
155
+ controlPlane: {
156
+ waveNumber: wave.wave,
157
+ attempt: dashboardState?.attempt || 1,
158
+ },
180
159
  });
181
160
  runInfo.lastLaunchAttempt = dashboardState?.attempt || null;
182
161
  runInfo.lastPromptHash = launchResult?.promptHash || null;
@@ -201,7 +180,7 @@ export async function runClosureSweepPhase({
201
180
  refreshWaveDashboardAgentStates(dashboardState, [runInfo], pendingAgentIds, (event) =>
202
181
  recordCombinedEvent(event),
203
182
  );
204
- const feedbackChanged = monitorWaveHumanFeedbackFn({
183
+ const feedbackChanged = monitorHumanFeedback({
205
184
  lanePaths,
206
185
  waveNumber: wave.wave,
207
186
  agentRuns: [runInfo],
@@ -217,14 +196,37 @@ export async function runClosureSweepPhase({
217
196
  updateWaveDashboardMessageBoard(dashboardState, runInfo.messageBoardPath);
218
197
  flushDashboards();
219
198
  },
199
+ {
200
+ controlPlane: {
201
+ waveNumber: wave.wave,
202
+ attempt: dashboardState?.attempt || 1,
203
+ },
204
+ },
220
205
  );
221
- materializeAgentExecutionSummaryForRunFn(wave, runInfo);
206
+ materializeSummary(wave, runInfo);
222
207
  refreshDerivedState?.(dashboardState?.attempt || 0);
223
208
  if (result.failures.length > 0) {
224
209
  return result;
225
210
  }
226
211
  }
227
- const gate = stage.validate();
212
+ const gate = evaluateClosureStage({
213
+ stage,
214
+ wave,
215
+ closureRuns,
216
+ lanePaths,
217
+ dashboardState,
218
+ refreshDerivedState,
219
+ readWaveContEvalGateFn: readContEvalGate,
220
+ readWaveSecurityGateFn: readSecurityGate,
221
+ readWaveIntegrationBarrierFn: readIntegrationBarrier,
222
+ readWaveDocumentationGateFn: readDocumentationGate,
223
+ readWaveComponentMatrixGateFn: readComponentMatrixGate,
224
+ readWaveContQaGateFn: readContQaGate,
225
+ contEvalAgentId,
226
+ integrationAgentId,
227
+ documentationAgentId,
228
+ contQaAgentId,
229
+ });
228
230
  if (!gate.ok) {
229
231
  recordClosureGateFailure({
230
232
  wave,
@@ -244,6 +246,120 @@ export async function runClosureSweepPhase({
244
246
  return { failures: [], timedOut: false };
245
247
  }
246
248
 
249
+ export function planClosureStages({ lanePaths, wave, closureRuns }) {
250
+ const { contQaAgentId, contEvalAgentId, integrationAgentId, documentationAgentId } =
251
+ resolveWaveRoleBindings(wave, lanePaths);
252
+ return [
253
+ {
254
+ key: "cont-eval",
255
+ agentId: contEvalAgentId,
256
+ label: "cont-EVAL gate",
257
+ runs: closureRuns.filter((run) => run.agent.agentId === contEvalAgentId),
258
+ actionRequested:
259
+ `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`,
260
+ },
261
+ {
262
+ key: "security-review",
263
+ agentId: "security",
264
+ label: "Security review",
265
+ runs: closureRuns.filter((run) => isSecurityReviewAgent(run.agent)),
266
+ actionRequested:
267
+ `Lane ${lanePaths.lane} owners should resolve blocked security findings or missing approvals before integration closure.`,
268
+ },
269
+ {
270
+ key: "integration",
271
+ agentId: integrationAgentId,
272
+ label: "Integration gate",
273
+ runs: closureRuns.filter((run) => run.agent.agentId === integrationAgentId),
274
+ actionRequested:
275
+ `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`,
276
+ },
277
+ {
278
+ key: "documentation",
279
+ agentId: documentationAgentId,
280
+ label: "Documentation closure",
281
+ runs: closureRuns.filter((run) => run.agent.agentId === documentationAgentId),
282
+ actionRequested:
283
+ `Lane ${lanePaths.lane} owners should resolve the shared-plan or component-matrix closure state before cont-QA progression.`,
284
+ },
285
+ {
286
+ key: "cont-qa",
287
+ agentId: contQaAgentId,
288
+ label: "cont-QA gate",
289
+ runs: closureRuns.filter((run) => run.agent.agentId === contQaAgentId),
290
+ actionRequested:
291
+ `Lane ${lanePaths.lane} owners should resolve the cont-QA gate before wave progression.`,
292
+ },
293
+ ];
294
+ }
295
+
296
+ function evaluateClosureStage({
297
+ stage,
298
+ wave,
299
+ closureRuns,
300
+ lanePaths,
301
+ dashboardState,
302
+ refreshDerivedState,
303
+ readWaveContEvalGateFn,
304
+ readWaveSecurityGateFn,
305
+ readWaveIntegrationBarrierFn,
306
+ readWaveDocumentationGateFn,
307
+ readWaveComponentMatrixGateFn,
308
+ readWaveContQaGateFn,
309
+ contEvalAgentId,
310
+ integrationAgentId,
311
+ documentationAgentId,
312
+ contQaAgentId,
313
+ }) {
314
+ switch (stage.key) {
315
+ case "cont-eval":
316
+ return readWaveContEvalGateFn(wave, closureRuns, {
317
+ contEvalAgentId,
318
+ mode: "live",
319
+ evalTargets: wave.evalTargets,
320
+ benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
321
+ });
322
+ case "security-review":
323
+ return readWaveSecurityGateFn(wave, closureRuns, { mode: "live" });
324
+ case "integration":
325
+ return readWaveIntegrationBarrierFn(
326
+ wave,
327
+ closureRuns,
328
+ refreshDerivedState?.(dashboardState?.attempt || 0),
329
+ {
330
+ integrationAgentId,
331
+ mode: "live",
332
+ requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
333
+ },
334
+ );
335
+ case "documentation": {
336
+ const documentationGate = readWaveDocumentationGateFn(wave, closureRuns, {
337
+ mode: "live",
338
+ });
339
+ if (!documentationGate.ok) {
340
+ return documentationGate;
341
+ }
342
+ return readWaveComponentMatrixGateFn(wave, closureRuns, {
343
+ laneProfile: lanePaths.laneProfile,
344
+ documentationAgentId,
345
+ });
346
+ }
347
+ case "cont-qa":
348
+ return readWaveContQaGateFn(wave, closureRuns, {
349
+ contQaAgentId,
350
+ mode: "live",
351
+ });
352
+ default:
353
+ return {
354
+ ok: true,
355
+ agentId: null,
356
+ statusCode: "pass",
357
+ detail: "No closure stage configured.",
358
+ logPath: null,
359
+ };
360
+ }
361
+ }
362
+
247
363
  const NON_BLOCKING_INFRA_SIGNAL_STATES = new Set([
248
364
  "conformant",
249
365
  "setup-required",
@@ -4,7 +4,7 @@ import {
4
4
  materializeAgentExecutionSummaryForRun,
5
5
  materializeAgentExecutionSummaries,
6
6
  readRunExecutionSummary,
7
- } from "./launcher-gates.mjs";
7
+ } from "./gate-engine.mjs";
8
8
  import {
9
9
  isOpenCoordinationStatus,
10
10
  appendCoordinationRecord,
@@ -13,9 +13,6 @@ import {
13
13
  readMaterializedCoordinationState,
14
14
  renderCoordinationBoardProjection,
15
15
  updateSeedRecords,
16
- writeCompiledInbox,
17
- writeCoordinationBoardProjection,
18
- writeJsonArtifact,
19
16
  buildCoordinationResponseMetrics,
20
17
  } from "./coordination-store.mjs";
21
18
  import { triageClarificationRequests } from "./clarification-triage.mjs";
@@ -24,29 +21,21 @@ import {
24
21
  buildRequestAssignments,
25
22
  renderDependencySnapshotMarkdown,
26
23
  syncAssignmentRecords,
27
- writeDependencySnapshotMarkdown,
28
24
  } from "./routing-state.mjs";
29
- import {
30
- writeAssignmentSnapshot,
31
- writeDependencySnapshot,
32
- } from "./artifact-schemas.mjs";
33
- import { deriveWaveLedger, readWaveLedger, writeWaveLedger } from "./ledger.mjs";
34
- import { buildDocsQueue, readDocsQueue, writeDocsQueue } from "./docs-queue.mjs";
35
- import {
36
- parseStructuredSignalsFromLog,
37
- } from "./dashboard-state.mjs";
25
+ import { deriveWaveLedger, readWaveLedger } from "./ledger.mjs";
26
+ import { buildDocsQueue, readDocsQueue } from "./docs-queue.mjs";
27
+ import { parseStructuredSignalsFromLog } from "./dashboard-state.mjs";
38
28
  import {
39
29
  isSecurityReviewAgent,
40
30
  resolveSecurityReviewReportPath,
41
31
  isContEvalImplementationOwningAgent,
32
+ resolveWaveRoleBindings,
42
33
  } from "./role-helpers.mjs";
43
34
  import {
44
35
  REPO_ROOT,
45
36
  compactSingleLine,
46
- ensureDirectory,
47
37
  readJsonOrNull,
48
38
  toIsoTimestamp,
49
- writeTextAtomic,
50
39
  } from "./shared.mjs";
51
40
  import {
52
41
  validateContEvalSummary,
@@ -307,27 +296,6 @@ export function buildWaveSecuritySummary({
307
296
  };
308
297
  }
309
298
 
310
- function renderWaveSecuritySummaryMarkdown(securitySummary) {
311
- return [
312
- `# Wave ${securitySummary.wave} Security Summary`,
313
- "",
314
- `- State: ${securitySummary.overallState || "unknown"}`,
315
- `- Detail: ${securitySummary.detail || "n/a"}`,
316
- `- Total findings: ${securitySummary.totalFindings || 0}`,
317
- `- Total approvals: ${securitySummary.totalApprovals || 0}`,
318
- `- Reviewers: ${(securitySummary.agents || []).length}`,
319
- "",
320
- "## Reviews",
321
- ...((securitySummary.agents || []).length > 0
322
- ? securitySummary.agents.map(
323
- (entry) =>
324
- `- ${entry.agentId}: state=${entry.state || "unknown"} findings=${entry.findings || 0} approvals=${entry.approvals || 0}${entry.reportPath ? ` report=${entry.reportPath}` : ""}${entry.detail ? ` detail=${entry.detail}` : ""}`,
325
- )
326
- : ["- None."]),
327
- "",
328
- ].join("\n");
329
- }
330
-
331
299
  function padReportedEntries(entries, minimumCount, label) {
332
300
  const padded = [...entries];
333
301
  for (let index = padded.length + 1; index <= minimumCount; index += 1) {
@@ -339,6 +307,7 @@ function padReportedEntries(entries, minimumCount, label) {
339
307
  function buildIntegrationEvidence({
340
308
  lanePaths,
341
309
  wave,
310
+ roleBindings = resolveWaveRoleBindings(wave, lanePaths),
342
311
  coordinationState,
343
312
  summariesByAgentId,
344
313
  docsQueue,
@@ -404,14 +373,14 @@ function buildIntegrationEvidence({
404
373
  for (const agent of wave.agents || []) {
405
374
  const summary = summariesByAgentId?.[agent.agentId] || null;
406
375
  const contEvalImplementationOwning =
407
- agent.agentId === lanePaths.contEvalAgentId &&
376
+ agent.agentId === roleBindings.contEvalAgentId &&
408
377
  isContEvalImplementationOwningAgent(agent, {
409
- contEvalAgentId: lanePaths.contEvalAgentId,
378
+ contEvalAgentId: roleBindings.contEvalAgentId,
410
379
  });
411
380
  if (isSecurityReviewAgent(agent)) {
412
381
  continue;
413
382
  }
414
- if (agent.agentId === lanePaths.contEvalAgentId) {
383
+ if (agent.agentId === roleBindings.contEvalAgentId) {
415
384
  const validation = validateContEvalSummary(agent, summary, {
416
385
  mode: "live",
417
386
  evalTargets: wave.evalTargets,
@@ -425,11 +394,11 @@ function buildIntegrationEvidence({
425
394
  }
426
395
  if (
427
396
  ![
428
- lanePaths.contQaAgentId,
429
- lanePaths.integrationAgentId,
430
- lanePaths.documentationAgentId,
397
+ roleBindings.contQaAgentId,
398
+ roleBindings.integrationAgentId,
399
+ roleBindings.documentationAgentId,
431
400
  ].includes(agent.agentId) &&
432
- (agent.agentId !== lanePaths.contEvalAgentId || contEvalImplementationOwning)
401
+ (agent.agentId !== roleBindings.contEvalAgentId || contEvalImplementationOwning)
433
402
  ) {
434
403
  const validation = validateImplementationSummary(agent, summary);
435
404
  if (!validation.ok) {
@@ -553,10 +522,12 @@ export function buildWaveIntegrationSummary({
553
522
  dependencySnapshot = null,
554
523
  securitySummary = null,
555
524
  }) {
556
- const explicitIntegration = summariesByAgentId[lanePaths.integrationAgentId]?.integration || null;
525
+ const roleBindings = resolveWaveRoleBindings(wave, lanePaths);
526
+ const explicitIntegration = summariesByAgentId[roleBindings.integrationAgentId]?.integration || null;
557
527
  const evidence = buildIntegrationEvidence({
558
528
  lanePaths,
559
529
  wave,
530
+ roleBindings,
560
531
  coordinationState,
561
532
  summariesByAgentId,
562
533
  docsQueue,
@@ -569,7 +540,7 @@ export function buildWaveIntegrationSummary({
569
540
  return {
570
541
  wave: wave.wave,
571
542
  lane: lanePaths.lane,
572
- agentId: lanePaths.integrationAgentId,
543
+ agentId: roleBindings.integrationAgentId,
573
544
  attempt,
574
545
  openClaims: padReportedEntries(
575
546
  evidence.openClaims,
@@ -619,63 +590,7 @@ export function buildWaveIntegrationSummary({
619
590
  };
620
591
  }
621
592
 
622
- function renderIntegrationSection(title, items) {
623
- return [
624
- title,
625
- ...((items || []).length > 0 ? items.map((item) => `- ${item}`) : ["- None."]),
626
- "",
627
- ];
628
- }
629
-
630
- function renderIntegrationSummaryMarkdown(integrationSummary) {
631
- return [
632
- `# Wave ${integrationSummary.wave} Integration Summary`,
633
- "",
634
- `- Recommendation: ${integrationSummary.recommendation || "unknown"}`,
635
- `- Detail: ${integrationSummary.detail || "n/a"}`,
636
- `- Open claims: ${(integrationSummary.openClaims || []).length}`,
637
- `- Conflicting claims: ${(integrationSummary.conflictingClaims || []).length}`,
638
- `- Unresolved blockers: ${(integrationSummary.unresolvedBlockers || []).length}`,
639
- `- Changed interfaces: ${(integrationSummary.changedInterfaces || []).length}`,
640
- `- Cross-component impacts: ${(integrationSummary.crossComponentImpacts || []).length}`,
641
- `- Proof gaps: ${(integrationSummary.proofGaps || []).length}`,
642
- `- Deploy risks: ${(integrationSummary.deployRisks || []).length}`,
643
- `- Documentation gaps: ${(integrationSummary.docGaps || []).length}`,
644
- `- Security review: ${integrationSummary.securityState || "not-applicable"}`,
645
- `- Security findings: ${(integrationSummary.securityFindings || []).length}`,
646
- `- Security approvals: ${(integrationSummary.securityApprovals || []).length}`,
647
- `- Inbound dependencies: ${(integrationSummary.inboundDependencies || []).length}`,
648
- `- Outbound dependencies: ${(integrationSummary.outboundDependencies || []).length}`,
649
- `- Helper assignments: ${(integrationSummary.helperAssignments || []).length}`,
650
- "",
651
- ...renderIntegrationSection("## Open Claims", integrationSummary.openClaims),
652
- ...renderIntegrationSection("## Conflicting Claims", integrationSummary.conflictingClaims),
653
- ...renderIntegrationSection("## Unresolved Blockers", integrationSummary.unresolvedBlockers),
654
- ...renderIntegrationSection("## Changed Interfaces", integrationSummary.changedInterfaces),
655
- ...renderIntegrationSection(
656
- "## Cross-Component Impacts",
657
- integrationSummary.crossComponentImpacts,
658
- ),
659
- ...renderIntegrationSection("## Proof Gaps", integrationSummary.proofGaps),
660
- ...renderIntegrationSection("## Deploy Risks", integrationSummary.deployRisks),
661
- ...renderIntegrationSection("## Security Findings", integrationSummary.securityFindings),
662
- ...renderIntegrationSection("## Security Approvals", integrationSummary.securityApprovals),
663
- ...renderIntegrationSection("## Inbound Dependencies", integrationSummary.inboundDependencies),
664
- ...renderIntegrationSection("## Outbound Dependencies", integrationSummary.outboundDependencies),
665
- ...renderIntegrationSection("## Helper Assignments", integrationSummary.helperAssignments),
666
- "## Runtime Assignments",
667
- ...((integrationSummary.runtimeAssignments || []).length > 0
668
- ? integrationSummary.runtimeAssignments.map(
669
- (assignment) =>
670
- `- ${assignment.agentId}: executor=${assignment.executorId || "n/a"} role=${assignment.role || "n/a"} profile=${assignment.profile || "none"} fallback_used=${assignment.fallbackUsed ? "yes" : "no"}`,
671
- )
672
- : ["- None."]),
673
- "",
674
- ...renderIntegrationSection("## Documentation Gaps", integrationSummary.docGaps),
675
- ].join("\n");
676
- }
677
-
678
- export function writeWaveDerivedState({
593
+ export function buildWaveDerivedState({
679
594
  lanePaths,
680
595
  wave,
681
596
  agentRuns = [],
@@ -684,6 +599,7 @@ export function writeWaveDerivedState({
684
599
  attempt = 0,
685
600
  orchestratorId = null,
686
601
  }) {
602
+ const roleBindings = resolveWaveRoleBindings(wave, lanePaths);
687
603
  const coordinationLogPath = waveCoordinationLogPath(lanePaths, wave.wave);
688
604
  const existingDocsQueue = readDocsQueue(waveDocsQueuePath(lanePaths, wave.wave));
689
605
  const existingIntegrationSummary = readJsonOrNull(waveIntegrationPath(lanePaths, wave.wave));
@@ -694,10 +610,10 @@ export function writeWaveDerivedState({
694
610
  agents: wave.agents,
695
611
  componentPromotions: wave.componentPromotions,
696
612
  sharedPlanDocs: lanePaths.sharedPlanDocs,
697
- contQaAgentId: lanePaths.contQaAgentId,
698
- contEvalAgentId: lanePaths.contEvalAgentId,
699
- integrationAgentId: lanePaths.integrationAgentId,
700
- documentationAgentId: lanePaths.documentationAgentId,
613
+ contQaAgentId: roleBindings.contQaAgentId,
614
+ contEvalAgentId: roleBindings.contEvalAgentId,
615
+ integrationAgentId: roleBindings.integrationAgentId,
616
+ documentationAgentId: roleBindings.documentationAgentId,
701
617
  feedbackRequests,
702
618
  });
703
619
  let coordinationState = readMaterializedCoordinationState(coordinationLogPath);
@@ -738,18 +654,6 @@ export function writeWaveDerivedState({
738
654
  ledger: existingLedger,
739
655
  capabilityRouting: lanePaths.capabilityRouting,
740
656
  });
741
- writeAssignmentSnapshot(waveAssignmentsPath(lanePaths, wave.wave), capabilityAssignments, {
742
- lane: lanePaths.lane,
743
- wave: wave.wave,
744
- });
745
- writeDependencySnapshot(waveDependencySnapshotPath(lanePaths, wave.wave), dependencySnapshot, {
746
- lane: lanePaths.lane,
747
- wave: wave.wave,
748
- });
749
- writeDependencySnapshotMarkdown(
750
- waveDependencySnapshotMarkdownPath(lanePaths, wave.wave),
751
- dependencySnapshot,
752
- );
753
657
  const runtimeAssignments = wave.agents.map((agent) => ({
754
658
  agentId: agent.agentId,
755
659
  role: agent.executorResolved?.role || null,
@@ -772,18 +676,12 @@ export function writeWaveDerivedState({
772
676
  componentPromotions: wave.componentPromotions,
773
677
  runtimeAssignments,
774
678
  });
775
- writeDocsQueue(waveDocsQueuePath(lanePaths, wave.wave), docsQueue);
776
679
  const securitySummary = buildWaveSecuritySummary({
777
680
  lanePaths,
778
681
  wave,
779
682
  attempt,
780
683
  summariesByAgentId,
781
684
  });
782
- writeJsonArtifact(waveSecurityPath(lanePaths, wave.wave), securitySummary);
783
- writeTextAtomic(
784
- waveSecurityMarkdownPath(lanePaths, wave.wave),
785
- `${renderWaveSecuritySummaryMarkdown(securitySummary)}\n`,
786
- );
787
685
  const integrationSummary = buildWaveIntegrationSummary({
788
686
  lanePaths,
789
687
  wave,
@@ -797,11 +695,6 @@ export function writeWaveDerivedState({
797
695
  dependencySnapshot,
798
696
  securitySummary,
799
697
  });
800
- writeJsonArtifact(waveIntegrationPath(lanePaths, wave.wave), integrationSummary);
801
- writeTextAtomic(
802
- waveIntegrationMarkdownPath(lanePaths, wave.wave),
803
- `${renderIntegrationSummaryMarkdown(integrationSummary)}\n`,
804
- );
805
698
  const ledger = deriveWaveLedger({
806
699
  lane: lanePaths.lane,
807
700
  wave,
@@ -810,17 +703,15 @@ export function writeWaveDerivedState({
810
703
  integrationSummary,
811
704
  docsQueue,
812
705
  attempt,
813
- contQaAgentId: lanePaths.contQaAgentId,
814
- contEvalAgentId: lanePaths.contEvalAgentId,
815
- integrationAgentId: lanePaths.integrationAgentId,
816
- documentationAgentId: lanePaths.documentationAgentId,
706
+ contQaAgentId: roleBindings.contQaAgentId,
707
+ contEvalAgentId: roleBindings.contEvalAgentId,
708
+ integrationAgentId: roleBindings.integrationAgentId,
709
+ documentationAgentId: roleBindings.documentationAgentId,
817
710
  benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
818
711
  capabilityAssignments,
819
712
  dependencySnapshot,
820
713
  });
821
- writeWaveLedger(waveLedgerPath(lanePaths, wave.wave), ledger);
822
714
  const inboxDir = waveInboxDir(lanePaths, wave.wave);
823
- ensureDirectory(inboxDir);
824
715
  const sharedSummary = compileSharedSummary({
825
716
  wave,
826
717
  state: coordinationState,
@@ -830,7 +721,6 @@ export function writeWaveDerivedState({
830
721
  dependencySnapshot,
831
722
  });
832
723
  const sharedSummaryPath = path.join(inboxDir, "shared-summary.md");
833
- writeCompiledInbox(sharedSummaryPath, sharedSummary.text);
834
724
  const inboxesByAgentId = {};
835
725
  for (const agent of wave.agents) {
836
726
  const inbox = compileAgentInbox({
@@ -844,7 +734,6 @@ export function writeWaveDerivedState({
844
734
  dependencySnapshot,
845
735
  });
846
736
  const inboxPath = path.join(inboxDir, `${agent.agentId}.md`);
847
- writeCompiledInbox(inboxPath, inbox.text);
848
737
  inboxesByAgentId[agent.agentId] = { path: inboxPath, text: inbox.text, truncated: inbox.truncated };
849
738
  }
850
739
  const boardText = renderCoordinationBoardProjection({
@@ -857,26 +746,25 @@ export function writeWaveDerivedState({
857
746
  });
858
747
  const responseMetrics = buildCoordinationResponseMetrics(coordinationState);
859
748
  const messageBoardPath = path.join(lanePaths.messageboardsDir, `wave-${wave.wave}.md`);
860
- writeCoordinationBoardProjection(messageBoardPath, {
861
- wave: wave.wave,
862
- waveFile: wave.file,
863
- agents: wave.agents,
864
- state: coordinationState,
865
- capabilityAssignments,
866
- dependencySnapshot,
867
- });
868
749
  return {
869
750
  coordinationLogPath,
870
751
  coordinationState,
871
752
  clarificationTriage,
872
753
  docsQueue,
754
+ docsQueuePath: waveDocsQueuePath(lanePaths, wave.wave),
873
755
  capabilityAssignments,
756
+ assignmentSnapshotPath: waveAssignmentsPath(lanePaths, wave.wave),
874
757
  dependencySnapshot,
758
+ dependencySnapshotPath: waveDependencySnapshotPath(lanePaths, wave.wave),
759
+ dependencySnapshotMarkdownPath: waveDependencySnapshotMarkdownPath(lanePaths, wave.wave),
875
760
  securitySummary,
761
+ securitySummaryPath: waveSecurityPath(lanePaths, wave.wave),
876
762
  integrationSummary,
763
+ integrationSummaryPath: waveIntegrationPath(lanePaths, wave.wave),
877
764
  integrationMarkdownPath: waveIntegrationMarkdownPath(lanePaths, wave.wave),
878
765
  securityMarkdownPath: waveSecurityMarkdownPath(lanePaths, wave.wave),
879
766
  ledger,
767
+ ledgerPath: waveLedgerPath(lanePaths, wave.wave),
880
768
  responseMetrics,
881
769
  sharedSummaryPath,
882
770
  sharedSummaryText: sharedSummary.text,