@chllming/wave-orchestration 0.8.2 → 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 (42) hide show
  1. package/CHANGELOG.md +40 -2
  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 +17 -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 -61
  10. package/docs/plans/wave-orchestrator.md +37 -11
  11. package/docs/reference/cli-reference.md +39 -15
  12. package/docs/reference/coordination-and-closure.md +30 -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 +39 -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/control-cli.mjs +8 -0
  21. package/scripts/wave-orchestrator/coord-cli.mjs +8 -0
  22. package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
  23. package/scripts/wave-orchestrator/feedback.mjs +11 -1
  24. package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +395 -139
  25. package/scripts/wave-orchestrator/human-input-resolution.mjs +348 -0
  26. package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
  27. package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
  28. package/scripts/wave-orchestrator/launcher-runtime.mjs +5 -6
  29. package/scripts/wave-orchestrator/launcher.mjs +271 -724
  30. package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
  31. package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
  32. package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
  33. package/scripts/wave-orchestrator/replay.mjs +3 -1
  34. package/scripts/wave-orchestrator/result-envelope.mjs +589 -0
  35. package/scripts/wave-orchestrator/retry-control.mjs +5 -0
  36. package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +267 -18
  37. package/scripts/wave-orchestrator/role-helpers.mjs +51 -0
  38. package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
  39. package/scripts/wave-orchestrator/shared.mjs +1 -0
  40. package/scripts/wave-orchestrator/traces.mjs +10 -1
  41. package/scripts/wave-orchestrator/wave-files.mjs +11 -9
  42. 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",
@@ -6,6 +6,7 @@ import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
6
6
  import { readWaveLedger } from "./ledger.mjs";
7
7
  import { buildDependencySnapshot, buildRequestAssignments } from "./routing-state.mjs";
8
8
  import { parseWaveFiles } from "./wave-files.mjs";
9
+ import { answerHumanInputAndReconcile } from "./human-input-resolution.mjs";
9
10
  import {
10
11
  buildLanePaths,
11
12
  DEFAULT_COORDINATION_ACK_TIMEOUT_MS,
@@ -1017,6 +1018,13 @@ export async function runControlCli(argv) {
1017
1018
  operator: options.operator,
1018
1019
  force: true,
1019
1020
  });
1021
+ answerHumanInputAndReconcile({
1022
+ lanePaths,
1023
+ wave,
1024
+ requestId: options.id,
1025
+ answeredPayload: answered,
1026
+ operator: options.operator,
1027
+ });
1020
1028
  appendWaveControlEvent(lanePaths, wave.wave, {
1021
1029
  entityType: "human_input",
1022
1030
  entityId: options.id,
@@ -23,6 +23,7 @@ import {
23
23
  writeJsonArtifact,
24
24
  } from "./coordination-store.mjs";
25
25
  import { answerFeedbackRequest } from "./feedback.mjs";
26
+ import { answerHumanInputAndReconcile } from "./human-input-resolution.mjs";
26
27
  import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
27
28
  import { readWaveProofRegistry } from "./proof-registry.mjs";
28
29
  import {
@@ -463,6 +464,13 @@ export async function runCoordinationCli(argv) {
463
464
  force: true,
464
465
  recordTelemetry: true,
465
466
  });
467
+ answerHumanInputAndReconcile({
468
+ lanePaths,
469
+ wave,
470
+ requestId: options.id,
471
+ answeredPayload: answered,
472
+ operator: options.operator,
473
+ });
466
474
  console.log(JSON.stringify(answered, null, 2));
467
475
  return;
468
476
  }