@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
|
@@ -3,10 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import {
|
|
4
4
|
agentSummaryPathFromStatusPath,
|
|
5
5
|
buildAgentExecutionSummary,
|
|
6
|
-
buildEnvelopeFromLegacySignals,
|
|
7
|
-
buildExecutionSummaryFromEnvelope,
|
|
8
6
|
readAgentExecutionSummary,
|
|
9
|
-
readAgentResultEnvelope,
|
|
10
7
|
validateContQaSummary,
|
|
11
8
|
validateContEvalSummary,
|
|
12
9
|
validateImplementationSummary,
|
|
@@ -14,8 +11,17 @@ import {
|
|
|
14
11
|
validateSecuritySummary,
|
|
15
12
|
validateIntegrationSummary,
|
|
16
13
|
writeAgentExecutionSummary,
|
|
17
|
-
writeAgentResultEnvelope,
|
|
18
14
|
} from "./agent-state.mjs";
|
|
15
|
+
import {
|
|
16
|
+
projectLegacySummaryFromEnvelope,
|
|
17
|
+
readAgentResultEnvelope,
|
|
18
|
+
readAgentResultEnvelopeForRun,
|
|
19
|
+
resolveRunEnvelopeContext,
|
|
20
|
+
synthesizeLegacyEnvelope,
|
|
21
|
+
validateResultEnvelope,
|
|
22
|
+
writeAgentResultEnvelope,
|
|
23
|
+
writeAgentResultEnvelopeForRun,
|
|
24
|
+
} from "./result-envelope.mjs";
|
|
19
25
|
import {
|
|
20
26
|
REPO_ROOT,
|
|
21
27
|
readFileTail,
|
|
@@ -91,6 +97,33 @@ function resolveRunReportPath(wave, runInfo) {
|
|
|
91
97
|
return null;
|
|
92
98
|
}
|
|
93
99
|
|
|
100
|
+
function normalizeReadMode(mode) {
|
|
101
|
+
return String(mode || "compat").trim().toLowerCase() === "live" ? "live" : "compat";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function buildEnvelopeReadOptions(runInfo, wave, statusRecord, reportPath) {
|
|
105
|
+
return {
|
|
106
|
+
agent: runInfo?.agent,
|
|
107
|
+
waveNumber: wave?.wave ?? null,
|
|
108
|
+
attempt: statusRecord?.attempt ?? null,
|
|
109
|
+
logPath: runInfo?.logPath || null,
|
|
110
|
+
reportPath,
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function validateEnvelopeForRun(runInfo, envelope, options = {}) {
|
|
115
|
+
const validation = validateResultEnvelope(envelope, {
|
|
116
|
+
agent: runInfo?.agent,
|
|
117
|
+
waveNumber: options.wave?.wave ?? null,
|
|
118
|
+
});
|
|
119
|
+
return {
|
|
120
|
+
valid: validation.valid,
|
|
121
|
+
errors: validation.errors || [],
|
|
122
|
+
detail: validation.valid ? null : validation.errors.join(" "),
|
|
123
|
+
envelope: validation.valid ? envelope : null,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
|
|
94
127
|
export function materializeAgentExecutionSummaryForRun(wave, runInfo) {
|
|
95
128
|
const statusRecord = readStatusRecordIfPresent(runInfo.statusPath);
|
|
96
129
|
if (!statusRecord) {
|
|
@@ -104,13 +137,17 @@ export function materializeAgentExecutionSummaryForRun(wave, runInfo) {
|
|
|
104
137
|
reportPath,
|
|
105
138
|
});
|
|
106
139
|
writeAgentExecutionSummary(runInfo.statusPath, summary);
|
|
107
|
-
|
|
108
|
-
runInfo
|
|
109
|
-
|
|
140
|
+
writeAgentResultEnvelopeForRun(
|
|
141
|
+
runInfo,
|
|
142
|
+
wave,
|
|
143
|
+
synthesizeLegacyEnvelope(runInfo.agent, summary, {
|
|
110
144
|
waveNumber: wave?.wave ?? null,
|
|
111
145
|
attempt: statusRecord.attempt ?? null,
|
|
112
146
|
exitCode: typeof statusRecord.code === "number" ? statusRecord.code : 0,
|
|
113
147
|
}),
|
|
148
|
+
{
|
|
149
|
+
statusRecord,
|
|
150
|
+
},
|
|
114
151
|
);
|
|
115
152
|
if (runInfo?.previewPath && fs.existsSync(runInfo.previewPath)) {
|
|
116
153
|
const previewPayload = readJsonOrNull(runInfo.previewPath);
|
|
@@ -141,48 +178,164 @@ export function materializeAgentExecutionSummaryForRun(wave, runInfo) {
|
|
|
141
178
|
return summary;
|
|
142
179
|
}
|
|
143
180
|
|
|
144
|
-
export function
|
|
145
|
-
const
|
|
146
|
-
runInfo?.proofRegistry ? augmentSummaryWithProofRegistry(runInfo.agent, summary, runInfo.proofRegistry) : summary;
|
|
181
|
+
export function readRunResultEnvelope(runInfo, wave = null, options = {}) {
|
|
182
|
+
const mode = normalizeReadMode(options.mode);
|
|
147
183
|
const statusRecord = runInfo?.statusPath ? readStatusRecordIfPresent(runInfo.statusPath) : null;
|
|
148
|
-
const reportPath = wave
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
:
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
184
|
+
const reportPath = wave ? resolveRunReportPath(wave, runInfo) : null;
|
|
185
|
+
const runEnvelopeContext = resolveRunEnvelopeContext(runInfo, wave, { statusRecord });
|
|
186
|
+
const envelopeReadOptions = buildEnvelopeReadOptions(runInfo, wave, statusRecord, reportPath);
|
|
187
|
+
const synthesizeFromSummary = (summary, source) => {
|
|
188
|
+
if (!summary || mode === "live") {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
const envelope = synthesizeLegacyEnvelope(runInfo?.agent, summary, {
|
|
192
|
+
waveNumber: wave?.wave ?? null,
|
|
193
|
+
attempt: statusRecord?.attempt ?? null,
|
|
194
|
+
exitCode:
|
|
195
|
+
typeof statusRecord?.code === "number"
|
|
196
|
+
? statusRecord.code
|
|
197
|
+
: typeof summary?.exitCode === "number"
|
|
198
|
+
? summary.exitCode
|
|
199
|
+
: 0,
|
|
200
|
+
});
|
|
201
|
+
return {
|
|
202
|
+
source,
|
|
203
|
+
...validateEnvelopeForRun(runInfo, envelope, { wave }),
|
|
204
|
+
};
|
|
165
205
|
};
|
|
206
|
+
|
|
166
207
|
if (runInfo?.summary && typeof runInfo.summary === "object") {
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
208
|
+
if (runInfo.summary.schemaVersion === 2) {
|
|
209
|
+
return {
|
|
210
|
+
source: "inline-envelope",
|
|
211
|
+
...validateEnvelopeForRun(runInfo, runInfo.summary, { wave }),
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
const synthesized = synthesizeFromSummary(runInfo.summary, "inline-legacy-summary");
|
|
215
|
+
if (synthesized) {
|
|
216
|
+
return synthesized;
|
|
217
|
+
}
|
|
171
218
|
}
|
|
172
219
|
if (runInfo?.statusPath && fs.existsSync(runInfo.statusPath)) {
|
|
220
|
+
const envelope = readAgentResultEnvelopeForRun(runInfo, wave, { statusRecord });
|
|
221
|
+
if (envelope) {
|
|
222
|
+
const validation = {
|
|
223
|
+
source: "run-envelope",
|
|
224
|
+
...validateEnvelopeForRun(runInfo, envelope, { wave }),
|
|
225
|
+
};
|
|
226
|
+
if (validation.valid || mode === "live") {
|
|
227
|
+
return validation;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (mode !== "live" && runInfo?.statusPath && fs.existsSync(runInfo.statusPath)) {
|
|
173
232
|
const envelope = readAgentResultEnvelope(runInfo.statusPath);
|
|
174
233
|
if (envelope) {
|
|
175
|
-
|
|
234
|
+
const validation = {
|
|
235
|
+
source: "legacy-status-envelope",
|
|
236
|
+
...validateEnvelopeForRun(runInfo, envelope, { wave }),
|
|
237
|
+
};
|
|
238
|
+
if (validation.valid) {
|
|
239
|
+
return validation;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (mode !== "live" && runInfo?.summaryPath && fs.existsSync(runInfo.summaryPath)) {
|
|
244
|
+
const summary = readAgentExecutionSummary(runInfo.summaryPath, {
|
|
245
|
+
agent: runInfo.agent,
|
|
246
|
+
statusPath: runInfo.summaryPath,
|
|
247
|
+
statusRecord,
|
|
248
|
+
logPath: runInfo.logPath,
|
|
249
|
+
reportPath,
|
|
250
|
+
});
|
|
251
|
+
const synthesized = synthesizeFromSummary(summary, "summary-file-legacy");
|
|
252
|
+
if (synthesized) {
|
|
253
|
+
return synthesized;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
if (
|
|
257
|
+
mode !== "live" &&
|
|
258
|
+
runInfo?.statusPath &&
|
|
259
|
+
fs.existsSync(agentSummaryPathFromStatusPath(runInfo.statusPath))
|
|
260
|
+
) {
|
|
261
|
+
const summary = readAgentExecutionSummary(runInfo.statusPath, {
|
|
262
|
+
agent: runInfo.agent,
|
|
263
|
+
statusPath: runInfo.statusPath,
|
|
264
|
+
statusRecord,
|
|
265
|
+
logPath: runInfo.logPath,
|
|
266
|
+
reportPath,
|
|
267
|
+
});
|
|
268
|
+
const synthesized = synthesizeFromSummary(summary, "status-summary-legacy");
|
|
269
|
+
if (synthesized) {
|
|
270
|
+
return synthesized;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
if (
|
|
274
|
+
mode !== "live" &&
|
|
275
|
+
wave &&
|
|
276
|
+
runInfo?.statusPath &&
|
|
277
|
+
runInfo?.logPath &&
|
|
278
|
+
fs.existsSync(runInfo.statusPath)
|
|
279
|
+
) {
|
|
280
|
+
materializeAgentExecutionSummaryForRun(wave, runInfo);
|
|
281
|
+
const envelope =
|
|
282
|
+
readAgentResultEnvelopeForRun(runInfo, wave, { statusRecord }) ||
|
|
283
|
+
readAgentResultEnvelope(runInfo.statusPath);
|
|
284
|
+
if (envelope) {
|
|
285
|
+
return {
|
|
286
|
+
source: "materialized-legacy-envelope",
|
|
287
|
+
...validateEnvelopeForRun(runInfo, envelope, { wave }),
|
|
288
|
+
};
|
|
176
289
|
}
|
|
177
290
|
}
|
|
291
|
+
return {
|
|
292
|
+
source: "missing-envelope",
|
|
293
|
+
valid: false,
|
|
294
|
+
errors: [
|
|
295
|
+
`Missing result envelope for ${runInfo?.agent?.agentId || "unknown-agent"} at ${path.relative(REPO_ROOT, runEnvelopeContext.envelopePath)}.`,
|
|
296
|
+
],
|
|
297
|
+
detail: `Missing result envelope for ${runInfo?.agent?.agentId || "unknown-agent"} at ${path.relative(REPO_ROOT, runEnvelopeContext.envelopePath)}.`,
|
|
298
|
+
envelope: null,
|
|
299
|
+
envelopeReadOptions,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export function readRunExecutionSummary(runInfo, wave = null, options = {}) {
|
|
304
|
+
const mode = normalizeReadMode(options.mode);
|
|
305
|
+
const applyProofRegistry = (summary) =>
|
|
306
|
+
runInfo?.proofRegistry ? augmentSummaryWithProofRegistry(runInfo.agent, summary, runInfo.proofRegistry) : summary;
|
|
307
|
+
const statusRecord = runInfo?.statusPath ? readStatusRecordIfPresent(runInfo.statusPath) : null;
|
|
308
|
+
const reportPath = wave ? resolveRunReportPath(wave, runInfo) : null;
|
|
309
|
+
const envelopeReadOptions = buildEnvelopeReadOptions(runInfo, wave, statusRecord, reportPath);
|
|
310
|
+
const envelopeResult = readRunResultEnvelope(runInfo, wave, { mode });
|
|
311
|
+
if (envelopeResult?.valid && envelopeResult.envelope) {
|
|
312
|
+
return applyProofRegistry(
|
|
313
|
+
projectLegacySummaryFromEnvelope(envelopeResult.envelope, envelopeReadOptions),
|
|
314
|
+
);
|
|
315
|
+
}
|
|
316
|
+
if (mode === "live") {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
if (runInfo?.summary && typeof runInfo.summary === "object") {
|
|
320
|
+
return applyProofRegistry(runInfo.summary);
|
|
321
|
+
}
|
|
178
322
|
if (runInfo?.summaryPath && fs.existsSync(runInfo.summaryPath)) {
|
|
179
|
-
return applyProofRegistry(readAgentExecutionSummary(runInfo.summaryPath,
|
|
323
|
+
return applyProofRegistry(readAgentExecutionSummary(runInfo.summaryPath, {
|
|
324
|
+
agent: runInfo.agent,
|
|
325
|
+
statusPath: runInfo.summaryPath,
|
|
326
|
+
statusRecord,
|
|
327
|
+
logPath: runInfo.logPath,
|
|
328
|
+
reportPath,
|
|
329
|
+
}));
|
|
180
330
|
}
|
|
181
331
|
if (runInfo?.statusPath && fs.existsSync(agentSummaryPathFromStatusPath(runInfo.statusPath))) {
|
|
182
|
-
return applyProofRegistry(readAgentExecutionSummary(runInfo.statusPath,
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
332
|
+
return applyProofRegistry(readAgentExecutionSummary(runInfo.statusPath, {
|
|
333
|
+
agent: runInfo.agent,
|
|
334
|
+
statusPath: runInfo.statusPath,
|
|
335
|
+
statusRecord,
|
|
336
|
+
logPath: runInfo.logPath,
|
|
337
|
+
reportPath,
|
|
338
|
+
}));
|
|
186
339
|
}
|
|
187
340
|
return null;
|
|
188
341
|
}
|
|
@@ -208,7 +361,18 @@ export function readWaveContQaGate(wave, agentRuns, options = {}) {
|
|
|
208
361
|
logPath: null,
|
|
209
362
|
};
|
|
210
363
|
}
|
|
211
|
-
const
|
|
364
|
+
const envelopeResult = readRunResultEnvelope(contQaRun, wave, { mode });
|
|
365
|
+
const summary = envelopeResult.valid
|
|
366
|
+
? projectLegacySummaryFromEnvelope(
|
|
367
|
+
envelopeResult.envelope,
|
|
368
|
+
buildEnvelopeReadOptions(
|
|
369
|
+
contQaRun,
|
|
370
|
+
wave,
|
|
371
|
+
contQaRun?.statusPath ? readStatusRecordIfPresent(contQaRun.statusPath) : null,
|
|
372
|
+
resolveRunReportPath(wave, contQaRun),
|
|
373
|
+
),
|
|
374
|
+
)
|
|
375
|
+
: readRunExecutionSummary(contQaRun, wave, { mode });
|
|
212
376
|
if (summary) {
|
|
213
377
|
const validation = validateContQaSummary(contQaRun.agent, summary, { mode });
|
|
214
378
|
return {
|
|
@@ -223,8 +387,13 @@ export function readWaveContQaGate(wave, agentRuns, options = {}) {
|
|
|
223
387
|
return {
|
|
224
388
|
ok: false,
|
|
225
389
|
agentId: contQaRun.agent.agentId,
|
|
226
|
-
statusCode:
|
|
227
|
-
|
|
390
|
+
statusCode:
|
|
391
|
+
envelopeResult.source === "missing-envelope"
|
|
392
|
+
? "missing-result-envelope"
|
|
393
|
+
: "invalid-result-envelope",
|
|
394
|
+
detail:
|
|
395
|
+
envelopeResult.detail ||
|
|
396
|
+
`Missing structured cont-QA result envelope for ${contQaRun.agent.agentId}.`,
|
|
228
397
|
logPath: path.relative(REPO_ROOT, contQaRun.logPath),
|
|
229
398
|
};
|
|
230
399
|
}
|
|
@@ -284,7 +453,18 @@ export function readWaveContEvalGate(wave, agentRuns, options = {}) {
|
|
|
284
453
|
logPath: null,
|
|
285
454
|
};
|
|
286
455
|
}
|
|
287
|
-
const
|
|
456
|
+
const envelopeResult = readRunResultEnvelope(contEvalRun, wave, { mode });
|
|
457
|
+
const summary = envelopeResult.valid
|
|
458
|
+
? projectLegacySummaryFromEnvelope(
|
|
459
|
+
envelopeResult.envelope,
|
|
460
|
+
buildEnvelopeReadOptions(
|
|
461
|
+
contEvalRun,
|
|
462
|
+
wave,
|
|
463
|
+
contEvalRun?.statusPath ? readStatusRecordIfPresent(contEvalRun.statusPath) : null,
|
|
464
|
+
resolveRunReportPath(wave, contEvalRun),
|
|
465
|
+
),
|
|
466
|
+
)
|
|
467
|
+
: readRunExecutionSummary(contEvalRun, wave, { mode });
|
|
288
468
|
if (summary) {
|
|
289
469
|
const validation = validateContEvalSummary(contEvalRun.agent, summary, {
|
|
290
470
|
mode,
|
|
@@ -302,8 +482,16 @@ export function readWaveContEvalGate(wave, agentRuns, options = {}) {
|
|
|
302
482
|
return {
|
|
303
483
|
ok: false,
|
|
304
484
|
agentId: contEvalRun.agent.agentId,
|
|
305
|
-
statusCode:
|
|
306
|
-
|
|
485
|
+
statusCode:
|
|
486
|
+
strict && envelopeResult.source !== "missing-envelope"
|
|
487
|
+
? "invalid-result-envelope"
|
|
488
|
+
: strict
|
|
489
|
+
? "missing-result-envelope"
|
|
490
|
+
: "missing-wave-eval",
|
|
491
|
+
detail:
|
|
492
|
+
strict && envelopeResult.detail
|
|
493
|
+
? envelopeResult.detail
|
|
494
|
+
: `Missing [wave-eval] marker for ${contEvalRun.agent.agentId}.`,
|
|
307
495
|
logPath: path.relative(REPO_ROOT, contEvalRun.logPath),
|
|
308
496
|
};
|
|
309
497
|
}
|
|
@@ -315,7 +503,8 @@ export function readWaveEvaluatorGate(wave, agentRuns, options = {}) {
|
|
|
315
503
|
});
|
|
316
504
|
}
|
|
317
505
|
|
|
318
|
-
export function readWaveImplementationGate(wave, agentRuns) {
|
|
506
|
+
export function readWaveImplementationGate(wave, agentRuns, options = {}) {
|
|
507
|
+
const mode = normalizeReadMode(options.mode || "live");
|
|
319
508
|
const contQaAgentId = wave.contQaAgentId || "A0";
|
|
320
509
|
const contEvalAgentId = wave.contEvalAgentId || "E0";
|
|
321
510
|
const integrationAgentId = wave.integrationAgentId || "A8";
|
|
@@ -328,7 +517,32 @@ export function readWaveImplementationGate(wave, agentRuns) {
|
|
|
328
517
|
) {
|
|
329
518
|
continue;
|
|
330
519
|
}
|
|
331
|
-
const
|
|
520
|
+
const envelopeResult = readRunResultEnvelope(runInfo, wave, { mode });
|
|
521
|
+
if (mode === "live" && !envelopeResult.valid) {
|
|
522
|
+
return {
|
|
523
|
+
ok: false,
|
|
524
|
+
agentId: runInfo.agent.agentId,
|
|
525
|
+
statusCode:
|
|
526
|
+
envelopeResult.source === "missing-envelope"
|
|
527
|
+
? "missing-result-envelope"
|
|
528
|
+
: "invalid-result-envelope",
|
|
529
|
+
detail:
|
|
530
|
+
envelopeResult.detail ||
|
|
531
|
+
`Missing structured implementation result envelope for ${runInfo.agent.agentId}.`,
|
|
532
|
+
logPath: path.relative(REPO_ROOT, runInfo.logPath),
|
|
533
|
+
};
|
|
534
|
+
}
|
|
535
|
+
const summary = envelopeResult.valid
|
|
536
|
+
? projectLegacySummaryFromEnvelope(
|
|
537
|
+
envelopeResult.envelope,
|
|
538
|
+
buildEnvelopeReadOptions(
|
|
539
|
+
runInfo,
|
|
540
|
+
wave,
|
|
541
|
+
runInfo?.statusPath ? readStatusRecordIfPresent(runInfo.statusPath) : null,
|
|
542
|
+
resolveRunReportPath(wave, runInfo),
|
|
543
|
+
),
|
|
544
|
+
)
|
|
545
|
+
: readRunExecutionSummary(runInfo, wave, { mode });
|
|
332
546
|
const validation = validateImplementationSummary(runInfo.agent, summary);
|
|
333
547
|
if (!validation.ok) {
|
|
334
548
|
return {
|
|
@@ -423,8 +637,12 @@ export function buildSharedComponentSiblingPendingFailure(componentState) {
|
|
|
423
637
|
}
|
|
424
638
|
|
|
425
639
|
export function readWaveComponentGate(wave, agentRuns, options = {}) {
|
|
640
|
+
const mode = normalizeReadMode(options.mode);
|
|
426
641
|
const summariesByAgentId = Object.fromEntries(
|
|
427
|
-
agentRuns.map((runInfo) => [
|
|
642
|
+
agentRuns.map((runInfo) => [
|
|
643
|
+
runInfo.agent.agentId,
|
|
644
|
+
readRunExecutionSummary(runInfo, wave, { mode }),
|
|
645
|
+
]),
|
|
428
646
|
);
|
|
429
647
|
const validation = validateWaveComponentPromotions(wave, summariesByAgentId, options);
|
|
430
648
|
const sharedPending = (wave.componentPromotions || [])
|
|
@@ -493,7 +711,8 @@ export function readWaveComponentMatrixGate(wave, agentRuns, options = {}) {
|
|
|
493
711
|
};
|
|
494
712
|
}
|
|
495
713
|
|
|
496
|
-
export function readWaveDocumentationGate(wave, agentRuns) {
|
|
714
|
+
export function readWaveDocumentationGate(wave, agentRuns, options = {}) {
|
|
715
|
+
const mode = normalizeReadMode(options.mode || "live");
|
|
497
716
|
const documentationAgentId = wave.documentationAgentId || "A9";
|
|
498
717
|
const docRun =
|
|
499
718
|
agentRuns.find((run) => run.agent.agentId === documentationAgentId) ?? null;
|
|
@@ -506,7 +725,32 @@ export function readWaveDocumentationGate(wave, agentRuns) {
|
|
|
506
725
|
logPath: null,
|
|
507
726
|
};
|
|
508
727
|
}
|
|
509
|
-
const
|
|
728
|
+
const envelopeResult = readRunResultEnvelope(docRun, wave, { mode });
|
|
729
|
+
if (mode === "live" && !envelopeResult.valid) {
|
|
730
|
+
return {
|
|
731
|
+
ok: false,
|
|
732
|
+
agentId: docRun.agent.agentId,
|
|
733
|
+
statusCode:
|
|
734
|
+
envelopeResult.source === "missing-envelope"
|
|
735
|
+
? "missing-result-envelope"
|
|
736
|
+
: "invalid-result-envelope",
|
|
737
|
+
detail:
|
|
738
|
+
envelopeResult.detail ||
|
|
739
|
+
`Missing structured documentation result envelope for ${docRun.agent.agentId}.`,
|
|
740
|
+
logPath: path.relative(REPO_ROOT, docRun.logPath),
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
const summary = envelopeResult.valid
|
|
744
|
+
? projectLegacySummaryFromEnvelope(
|
|
745
|
+
envelopeResult.envelope,
|
|
746
|
+
buildEnvelopeReadOptions(
|
|
747
|
+
docRun,
|
|
748
|
+
wave,
|
|
749
|
+
docRun?.statusPath ? readStatusRecordIfPresent(docRun.statusPath) : null,
|
|
750
|
+
resolveRunReportPath(wave, docRun),
|
|
751
|
+
),
|
|
752
|
+
)
|
|
753
|
+
: readRunExecutionSummary(docRun, wave, { mode });
|
|
510
754
|
const validation = validateDocumentationClosureSummary(docRun.agent, summary);
|
|
511
755
|
return {
|
|
512
756
|
ok: validation.ok,
|
|
@@ -517,7 +761,8 @@ export function readWaveDocumentationGate(wave, agentRuns) {
|
|
|
517
761
|
};
|
|
518
762
|
}
|
|
519
763
|
|
|
520
|
-
export function readWaveSecurityGate(wave, agentRuns) {
|
|
764
|
+
export function readWaveSecurityGate(wave, agentRuns, options = {}) {
|
|
765
|
+
const mode = normalizeReadMode(options.mode || "live");
|
|
521
766
|
const securityRuns = (agentRuns || []).filter((run) => isSecurityReviewAgent(run.agent));
|
|
522
767
|
if (securityRuns.length === 0) {
|
|
523
768
|
return {
|
|
@@ -530,7 +775,32 @@ export function readWaveSecurityGate(wave, agentRuns) {
|
|
|
530
775
|
}
|
|
531
776
|
const concernAgentIds = [];
|
|
532
777
|
for (const runInfo of securityRuns) {
|
|
533
|
-
const
|
|
778
|
+
const envelopeResult = readRunResultEnvelope(runInfo, wave, { mode });
|
|
779
|
+
if (mode === "live" && !envelopeResult.valid) {
|
|
780
|
+
return {
|
|
781
|
+
ok: false,
|
|
782
|
+
agentId: runInfo.agent.agentId,
|
|
783
|
+
statusCode:
|
|
784
|
+
envelopeResult.source === "missing-envelope"
|
|
785
|
+
? "missing-result-envelope"
|
|
786
|
+
: "invalid-result-envelope",
|
|
787
|
+
detail:
|
|
788
|
+
envelopeResult.detail ||
|
|
789
|
+
`Missing structured security result envelope for ${runInfo.agent.agentId}.`,
|
|
790
|
+
logPath: path.relative(REPO_ROOT, runInfo.logPath),
|
|
791
|
+
};
|
|
792
|
+
}
|
|
793
|
+
const summary = envelopeResult.valid
|
|
794
|
+
? projectLegacySummaryFromEnvelope(
|
|
795
|
+
envelopeResult.envelope,
|
|
796
|
+
buildEnvelopeReadOptions(
|
|
797
|
+
runInfo,
|
|
798
|
+
wave,
|
|
799
|
+
runInfo?.statusPath ? readStatusRecordIfPresent(runInfo.statusPath) : null,
|
|
800
|
+
resolveRunReportPath(wave, runInfo),
|
|
801
|
+
),
|
|
802
|
+
)
|
|
803
|
+
: readRunExecutionSummary(runInfo, wave, { mode });
|
|
534
804
|
const validation = validateSecuritySummary(runInfo.agent, summary);
|
|
535
805
|
if (!validation.ok) {
|
|
536
806
|
return {
|
|
@@ -564,6 +834,7 @@ export function readWaveSecurityGate(wave, agentRuns) {
|
|
|
564
834
|
}
|
|
565
835
|
|
|
566
836
|
export function readWaveIntegrationGate(wave, agentRuns, options = {}) {
|
|
837
|
+
const mode = normalizeReadMode(options.mode || "live");
|
|
567
838
|
const integrationAgentId =
|
|
568
839
|
options.integrationAgentId || wave.integrationAgentId || "A8";
|
|
569
840
|
const requireIntegration =
|
|
@@ -584,7 +855,32 @@ export function readWaveIntegrationGate(wave, agentRuns, options = {}) {
|
|
|
584
855
|
logPath: null,
|
|
585
856
|
};
|
|
586
857
|
}
|
|
587
|
-
const
|
|
858
|
+
const envelopeResult = readRunResultEnvelope(integrationRun, wave, { mode });
|
|
859
|
+
if (mode === "live" && !envelopeResult.valid) {
|
|
860
|
+
return {
|
|
861
|
+
ok: false,
|
|
862
|
+
agentId: integrationRun.agent.agentId,
|
|
863
|
+
statusCode:
|
|
864
|
+
envelopeResult.source === "missing-envelope"
|
|
865
|
+
? "missing-result-envelope"
|
|
866
|
+
: "invalid-result-envelope",
|
|
867
|
+
detail:
|
|
868
|
+
envelopeResult.detail ||
|
|
869
|
+
`Missing structured integration result envelope for ${integrationRun.agent.agentId}.`,
|
|
870
|
+
logPath: path.relative(REPO_ROOT, integrationRun.logPath),
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
const summary = envelopeResult.valid
|
|
874
|
+
? projectLegacySummaryFromEnvelope(
|
|
875
|
+
envelopeResult.envelope,
|
|
876
|
+
buildEnvelopeReadOptions(
|
|
877
|
+
integrationRun,
|
|
878
|
+
wave,
|
|
879
|
+
integrationRun?.statusPath ? readStatusRecordIfPresent(integrationRun.statusPath) : null,
|
|
880
|
+
resolveRunReportPath(wave, integrationRun),
|
|
881
|
+
),
|
|
882
|
+
)
|
|
883
|
+
: readRunExecutionSummary(integrationRun, wave, { mode });
|
|
588
884
|
const validation = validateIntegrationSummary(integrationRun.agent, summary);
|
|
589
885
|
return {
|
|
590
886
|
ok: validation.ok,
|
|
@@ -737,91 +1033,51 @@ export function buildGateSnapshot({
|
|
|
737
1033
|
validationMode = "compat",
|
|
738
1034
|
readWaveInfraGateFn,
|
|
739
1035
|
}) {
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
1036
|
+
const agentResults = Object.fromEntries(
|
|
1037
|
+
(agentRuns || [])
|
|
1038
|
+
.map((runInfo) => [
|
|
1039
|
+
runInfo.agent.agentId,
|
|
1040
|
+
readRunExecutionSummary(runInfo, wave, { mode: validationMode }),
|
|
1041
|
+
])
|
|
1042
|
+
.filter(([, summary]) => Boolean(summary)),
|
|
1043
|
+
);
|
|
1044
|
+
return buildGateSnapshotPure({
|
|
1045
|
+
wave,
|
|
1046
|
+
agentResults,
|
|
1047
|
+
derivedState: {
|
|
1048
|
+
...derivedState,
|
|
1049
|
+
clarificationBarrier:
|
|
1050
|
+
derivedState?.clarificationBarrier || readClarificationBarrier(derivedState),
|
|
1051
|
+
helperAssignmentBarrier:
|
|
1052
|
+
derivedState?.helperAssignmentBarrier || readWaveAssignmentBarrier(derivedState),
|
|
1053
|
+
dependencyBarrier:
|
|
1054
|
+
derivedState?.dependencyBarrier || readWaveDependencyBarrier(derivedState),
|
|
1055
|
+
},
|
|
1056
|
+
validationMode,
|
|
1057
|
+
laneConfig: {
|
|
1058
|
+
contQaAgentId: lanePaths?.contQaAgentId,
|
|
1059
|
+
contEvalAgentId: lanePaths?.contEvalAgentId,
|
|
1060
|
+
integrationAgentId: lanePaths?.integrationAgentId,
|
|
1061
|
+
documentationAgentId: lanePaths?.documentationAgentId,
|
|
1062
|
+
requireIntegrationStewardFromWave: lanePaths?.requireIntegrationStewardFromWave,
|
|
1063
|
+
laneProfile: lanePaths?.laneProfile,
|
|
1064
|
+
benchmarkCatalogPath: lanePaths?.laneProfile?.paths?.benchmarkCatalogPath,
|
|
1065
|
+
componentMatrixPayload,
|
|
1066
|
+
componentMatrixJsonPath,
|
|
1067
|
+
},
|
|
769
1068
|
});
|
|
770
|
-
const infraGate = readWaveInfraGateFn(agentRuns);
|
|
771
|
-
const clarificationBarrier = readClarificationBarrier(derivedState);
|
|
772
|
-
const helperAssignmentBarrier = readWaveAssignmentBarrier(derivedState);
|
|
773
|
-
const dependencyBarrier = readWaveDependencyBarrier(derivedState);
|
|
774
|
-
const orderedGates = [
|
|
775
|
-
["implementationGate", implementationGate],
|
|
776
|
-
["componentGate", componentGate],
|
|
777
|
-
["helperAssignmentBarrier", helperAssignmentBarrier],
|
|
778
|
-
["dependencyBarrier", dependencyBarrier],
|
|
779
|
-
["contEvalGate", contEvalGate],
|
|
780
|
-
["securityGate", securityGate],
|
|
781
|
-
["integrationBarrier", integrationBarrier],
|
|
782
|
-
["documentationGate", documentationGate],
|
|
783
|
-
["componentMatrixGate", componentMatrixGate],
|
|
784
|
-
["contQaGate", contQaGate],
|
|
785
|
-
["infraGate", infraGate],
|
|
786
|
-
["clarificationBarrier", clarificationBarrier],
|
|
787
|
-
];
|
|
788
|
-
const firstFailure = orderedGates.find(([, gate]) => gate?.ok === false);
|
|
789
|
-
return {
|
|
790
|
-
implementationGate,
|
|
791
|
-
componentGate,
|
|
792
|
-
integrationGate,
|
|
793
|
-
integrationBarrier,
|
|
794
|
-
documentationGate,
|
|
795
|
-
componentMatrixGate,
|
|
796
|
-
contEvalGate,
|
|
797
|
-
securityGate,
|
|
798
|
-
contQaGate,
|
|
799
|
-
infraGate,
|
|
800
|
-
clarificationBarrier,
|
|
801
|
-
helperAssignmentBarrier,
|
|
802
|
-
dependencyBarrier,
|
|
803
|
-
overall: firstFailure
|
|
804
|
-
? {
|
|
805
|
-
ok: false,
|
|
806
|
-
gate: firstFailure[0],
|
|
807
|
-
statusCode: firstFailure[1].statusCode,
|
|
808
|
-
detail: firstFailure[1].detail,
|
|
809
|
-
agentId: firstFailure[1].agentId || null,
|
|
810
|
-
}
|
|
811
|
-
: {
|
|
812
|
-
ok: true,
|
|
813
|
-
gate: "pass",
|
|
814
|
-
statusCode: "pass",
|
|
815
|
-
detail: "All replayed wave gates passed.",
|
|
816
|
-
agentId: null,
|
|
817
|
-
},
|
|
818
|
-
};
|
|
819
1069
|
}
|
|
820
1070
|
|
|
821
1071
|
// --- Pure gate variants (no file I/O) ---
|
|
822
1072
|
// These accept agentResults map { agentId: executionSummary } instead of runInfo objects.
|
|
823
1073
|
// Used by the wave-state-reducer for deterministic replay.
|
|
824
1074
|
|
|
1075
|
+
function waveDeclaresAgent(wave, agentId) {
|
|
1076
|
+
return (Array.isArray(wave?.agents) ? wave.agents : []).some(
|
|
1077
|
+
(agent) => agent?.agentId === agentId,
|
|
1078
|
+
);
|
|
1079
|
+
}
|
|
1080
|
+
|
|
825
1081
|
export function readWaveImplementationGatePure(wave, agentResults, options = {}) {
|
|
826
1082
|
const contQaAgentId = options.contQaAgentId || wave.contQaAgentId || "A0";
|
|
827
1083
|
const contEvalAgentId = options.contEvalAgentId || wave.contEvalAgentId || "E0";
|
|
@@ -865,24 +1121,24 @@ export function readWaveContQaGatePure(wave, agentResults, options = {}) {
|
|
|
865
1121
|
const agent = { agentId: contQaAgentId };
|
|
866
1122
|
const validation = validateContQaSummary(agent, summary, { mode });
|
|
867
1123
|
return { ok: validation.ok, agentId: contQaAgentId, statusCode: validation.statusCode,
|
|
868
|
-
detail: validation.detail, logPath: summary
|
|
1124
|
+
detail: validation.detail, logPath: summary?.logPath || null };
|
|
869
1125
|
}
|
|
870
1126
|
|
|
871
1127
|
export function readWaveContEvalGatePure(wave, agentResults, options = {}) {
|
|
872
1128
|
const mode = String(options.mode || "live").trim().toLowerCase();
|
|
873
1129
|
const contEvalAgentId = options.contEvalAgentId || wave.contEvalAgentId || "E0";
|
|
874
|
-
|
|
875
|
-
if (!summary) {
|
|
1130
|
+
if (!waveDeclaresAgent(wave, contEvalAgentId)) {
|
|
876
1131
|
return { ok: true, agentId: null, statusCode: "pass",
|
|
877
1132
|
detail: "Wave does not include cont-EVAL.", logPath: null };
|
|
878
1133
|
}
|
|
1134
|
+
const summary = agentResults?.[contEvalAgentId] || null;
|
|
879
1135
|
const agent = { agentId: contEvalAgentId };
|
|
880
1136
|
const validation = validateContEvalSummary(agent, summary, {
|
|
881
1137
|
mode, evalTargets: options.evalTargets || wave.evalTargets,
|
|
882
1138
|
benchmarkCatalogPath: options.benchmarkCatalogPath,
|
|
883
1139
|
});
|
|
884
1140
|
return { ok: validation.ok, agentId: contEvalAgentId, statusCode: validation.statusCode,
|
|
885
|
-
detail: validation.detail, logPath: summary
|
|
1141
|
+
detail: validation.detail, logPath: summary?.logPath || null };
|
|
886
1142
|
}
|
|
887
1143
|
|
|
888
1144
|
export function readWaveEvaluatorGatePure(wave, agentResults, options = {}) {
|
|
@@ -976,15 +1232,15 @@ export function readWaveComponentMatrixGatePure(wave, agentResults, options = {}
|
|
|
976
1232
|
|
|
977
1233
|
export function readWaveDocumentationGatePure(wave, agentResults, options = {}) {
|
|
978
1234
|
const documentationAgentId = options.documentationAgentId || wave.documentationAgentId || "A9";
|
|
979
|
-
|
|
980
|
-
if (!summary) {
|
|
1235
|
+
if (!waveDeclaresAgent(wave, documentationAgentId)) {
|
|
981
1236
|
return { ok: true, agentId: null, statusCode: "pass",
|
|
982
1237
|
detail: "No documentation steward declared for this wave.", logPath: null };
|
|
983
1238
|
}
|
|
1239
|
+
const summary = agentResults?.[documentationAgentId] || null;
|
|
984
1240
|
const agent = { agentId: documentationAgentId };
|
|
985
1241
|
const validation = validateDocumentationClosureSummary(agent, summary);
|
|
986
1242
|
return { ok: validation.ok, agentId: documentationAgentId, statusCode: validation.statusCode,
|
|
987
|
-
detail: validation.detail, logPath: summary
|
|
1243
|
+
detail: validation.detail, logPath: summary?.logPath || null };
|
|
988
1244
|
}
|
|
989
1245
|
|
|
990
1246
|
export function readWaveSecurityGatePure(wave, agentResults, options = {}) {
|
|
@@ -1016,8 +1272,7 @@ export function readWaveIntegrationGatePure(wave, agentResults, options = {}) {
|
|
|
1016
1272
|
const integrationAgentId = options.integrationAgentId || wave.integrationAgentId || "A8";
|
|
1017
1273
|
const requireIntegration = options.requireIntegrationSteward === true ||
|
|
1018
1274
|
(options.requireIntegrationStewardFromWave != null && wave.wave >= options.requireIntegrationStewardFromWave);
|
|
1019
|
-
|
|
1020
|
-
if (!summary) {
|
|
1275
|
+
if (!waveDeclaresAgent(wave, integrationAgentId)) {
|
|
1021
1276
|
return {
|
|
1022
1277
|
ok: !requireIntegration,
|
|
1023
1278
|
agentId: requireIntegration ? integrationAgentId : null,
|
|
@@ -1027,10 +1282,11 @@ export function readWaveIntegrationGatePure(wave, agentResults, options = {}) {
|
|
|
1027
1282
|
logPath: null,
|
|
1028
1283
|
};
|
|
1029
1284
|
}
|
|
1285
|
+
const summary = agentResults?.[integrationAgentId] || null;
|
|
1030
1286
|
const agent = { agentId: integrationAgentId };
|
|
1031
1287
|
const validation = validateIntegrationSummary(agent, summary);
|
|
1032
1288
|
return { ok: validation.ok, agentId: integrationAgentId, statusCode: validation.statusCode,
|
|
1033
|
-
detail: validation.detail, logPath: summary
|
|
1289
|
+
detail: validation.detail, logPath: summary?.logPath || null };
|
|
1034
1290
|
}
|
|
1035
1291
|
|
|
1036
1292
|
const NON_BLOCKING_INFRA_SIGNAL_STATES = new Set([
|