@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.
- package/CHANGELOG.md +40 -2
- package/README.md +47 -11
- package/docs/README.md +6 -2
- package/docs/concepts/what-is-a-wave.md +1 -1
- package/docs/plans/architecture-hardening-migration.md +8 -1
- package/docs/plans/current-state.md +17 -7
- package/docs/plans/end-state-architecture.md +82 -69
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +235 -61
- package/docs/plans/wave-orchestrator.md +37 -11
- package/docs/reference/cli-reference.md +39 -15
- package/docs/reference/coordination-and-closure.md +30 -6
- package/docs/reference/npmjs-trusted-publishing.md +5 -4
- package/docs/reference/sample-waves.md +4 -4
- package/package.json +1 -1
- package/releases/manifest.json +39 -0
- package/scripts/wave-orchestrator/agent-state.mjs +0 -491
- package/scripts/wave-orchestrator/autonomous.mjs +10 -6
- package/scripts/wave-orchestrator/{launcher-closure.mjs → closure-engine.mjs} +190 -74
- package/scripts/wave-orchestrator/control-cli.mjs +8 -0
- package/scripts/wave-orchestrator/coord-cli.mjs +8 -0
- package/scripts/wave-orchestrator/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
- package/scripts/wave-orchestrator/feedback.mjs +11 -1
- package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +395 -139
- package/scripts/wave-orchestrator/human-input-resolution.mjs +348 -0
- package/scripts/wave-orchestrator/human-input-workflow.mjs +104 -0
- package/scripts/wave-orchestrator/implementation-engine.mjs +120 -0
- package/scripts/wave-orchestrator/launcher-runtime.mjs +5 -6
- package/scripts/wave-orchestrator/launcher.mjs +271 -724
- package/scripts/wave-orchestrator/projection-writer.mjs +256 -0
- package/scripts/wave-orchestrator/reconcile-format.mjs +32 -0
- package/scripts/wave-orchestrator/reducer-snapshot.mjs +297 -0
- package/scripts/wave-orchestrator/replay.mjs +3 -1
- package/scripts/wave-orchestrator/result-envelope.mjs +589 -0
- package/scripts/wave-orchestrator/retry-control.mjs +5 -0
- package/scripts/wave-orchestrator/{launcher-retry.mjs → retry-engine.mjs} +267 -18
- package/scripts/wave-orchestrator/role-helpers.mjs +51 -0
- package/scripts/wave-orchestrator/{launcher-supervisor.mjs → session-supervisor.mjs} +178 -103
- package/scripts/wave-orchestrator/shared.mjs +1 -0
- package/scripts/wave-orchestrator/traces.mjs +10 -1
- package/scripts/wave-orchestrator/wave-files.mjs +11 -9
- 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
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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 =
|
|
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
|
-
|
|
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 =
|
|
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
|
}
|