@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.
- package/CHANGELOG.md +19 -0
- 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 +15 -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 -62
- package/docs/plans/wave-orchestrator.md +37 -11
- package/docs/reference/cli-reference.md +34 -14
- package/docs/reference/coordination-and-closure.md +19 -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 +20 -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/{launcher-derived-state.mjs → derived-state-engine.mjs} +34 -146
- package/scripts/wave-orchestrator/{launcher-gates.mjs → gate-engine.mjs} +395 -139
- package/scripts/wave-orchestrator/human-input-resolution.mjs +14 -10
- 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
|
@@ -11,24 +11,12 @@ import {
|
|
|
11
11
|
} from "./config.mjs";
|
|
12
12
|
import {
|
|
13
13
|
appendOrchestratorBoardEntry,
|
|
14
|
-
buildResidentOrchestratorPrompt,
|
|
15
14
|
ensureOrchestratorBoard,
|
|
16
15
|
feedbackStateSignature,
|
|
17
16
|
readWaveHumanFeedbackRequests,
|
|
18
17
|
} from "./coordination.mjs";
|
|
19
18
|
import {
|
|
20
|
-
appendCoordinationRecord,
|
|
21
19
|
buildCoordinationResponseMetrics,
|
|
22
|
-
compileAgentInbox,
|
|
23
|
-
compileSharedSummary,
|
|
24
|
-
isOpenCoordinationStatus,
|
|
25
|
-
openClarificationLinkedRequests,
|
|
26
|
-
readMaterializedCoordinationState,
|
|
27
|
-
renderCoordinationBoardProjection,
|
|
28
|
-
updateSeedRecords,
|
|
29
|
-
writeCompiledInbox,
|
|
30
|
-
writeCoordinationBoardProjection,
|
|
31
|
-
writeJsonArtifact,
|
|
32
20
|
} from "./coordination-store.mjs";
|
|
33
21
|
import {
|
|
34
22
|
applyContext7SelectionsToWave,
|
|
@@ -40,16 +28,12 @@ import {
|
|
|
40
28
|
buildGlobalDashboardState,
|
|
41
29
|
buildWaveDashboardState,
|
|
42
30
|
getGlobalWaveEntry,
|
|
43
|
-
parseStructuredSignalsFromLog,
|
|
44
31
|
readStatusCodeIfPresent,
|
|
45
32
|
recordGlobalDashboardEvent,
|
|
46
33
|
recordWaveDashboardEvent,
|
|
47
34
|
refreshWaveDashboardAgentStates,
|
|
48
35
|
setWaveDashboardAgent,
|
|
49
|
-
syncGlobalWaveFromWaveDashboard,
|
|
50
36
|
updateWaveDashboardMessageBoard,
|
|
51
|
-
writeGlobalDashboard,
|
|
52
|
-
writeWaveDashboard,
|
|
53
37
|
} from "./dashboard-state.mjs";
|
|
54
38
|
import {
|
|
55
39
|
DEFAULT_AGENT_LAUNCH_STAGGER_MS,
|
|
@@ -61,7 +45,6 @@ import {
|
|
|
61
45
|
DEFAULT_MAX_RETRIES_PER_WAVE,
|
|
62
46
|
DEFAULT_TIMEOUT_MINUTES,
|
|
63
47
|
DEFAULT_WAVE_LANE,
|
|
64
|
-
compactSingleLine,
|
|
65
48
|
parseVerdictFromText,
|
|
66
49
|
readStatusRecordIfPresent,
|
|
67
50
|
REPO_ROOT,
|
|
@@ -131,8 +114,6 @@ import {
|
|
|
131
114
|
validateSecuritySummary,
|
|
132
115
|
writeAgentExecutionSummary,
|
|
133
116
|
} from "./agent-state.mjs";
|
|
134
|
-
import { buildDocsQueue, readDocsQueue, writeDocsQueue } from "./docs-queue.mjs";
|
|
135
|
-
import { deriveWaveLedger, readWaveLedger, writeWaveLedger } from "./ledger.mjs";
|
|
136
117
|
import {
|
|
137
118
|
augmentSummaryWithProofRegistry,
|
|
138
119
|
readWaveProofRegistry,
|
|
@@ -140,41 +121,23 @@ import {
|
|
|
140
121
|
} from "./proof-registry.mjs";
|
|
141
122
|
import {
|
|
142
123
|
clearWaveRetryOverride,
|
|
143
|
-
readWaveRelaunchPlanSnapshot,
|
|
144
124
|
readWaveRetryOverride,
|
|
145
|
-
resolveRetryOverrideRuns,
|
|
146
|
-
waveRelaunchPlanPath,
|
|
147
125
|
} from "./retry-control.mjs";
|
|
148
126
|
import { appendWaveControlEvent, readControlPlaneEvents } from "./control-plane.mjs";
|
|
149
127
|
import { materializeContradictionsFromControlPlaneEvents } from "./contradiction-entity.mjs";
|
|
150
|
-
import { buildQualityMetrics, writeTraceBundle } from "./traces.mjs";
|
|
151
128
|
import { flushWaveControlQueue } from "./wave-control-client.mjs";
|
|
152
|
-
import { reduceWaveState } from "./wave-state-reducer.mjs";
|
|
153
|
-
import { triageClarificationRequests } from "./clarification-triage.mjs";
|
|
154
129
|
import { readProjectProfile, resolveDefaultTerminalSurface } from "./project-profile.mjs";
|
|
155
130
|
import {
|
|
156
131
|
isContEvalImplementationOwningAgent,
|
|
157
132
|
isContEvalReportOnlyAgent,
|
|
133
|
+
isClosureRoleAgentId,
|
|
158
134
|
isSecurityReviewAgent,
|
|
135
|
+
resolveWaveRoleBindings,
|
|
159
136
|
resolveSecurityReviewReportPath,
|
|
160
137
|
} from "./role-helpers.mjs";
|
|
161
138
|
import {
|
|
162
139
|
summarizeResolvedSkills,
|
|
163
140
|
} from "./skills.mjs";
|
|
164
|
-
import {
|
|
165
|
-
buildDependencySnapshot,
|
|
166
|
-
buildRequestAssignments,
|
|
167
|
-
renderDependencySnapshotMarkdown,
|
|
168
|
-
syncAssignmentRecords,
|
|
169
|
-
writeDependencySnapshotMarkdown,
|
|
170
|
-
} from "./routing-state.mjs";
|
|
171
|
-
import {
|
|
172
|
-
readWaveStateSnapshot,
|
|
173
|
-
writeAssignmentSnapshot,
|
|
174
|
-
writeDependencySnapshot,
|
|
175
|
-
writeRelaunchPlan,
|
|
176
|
-
writeWaveStateSnapshot,
|
|
177
|
-
} from "./artifact-schemas.mjs";
|
|
178
141
|
import {
|
|
179
142
|
collectUnexpectedSessionFailures as collectUnexpectedSessionFailuresImpl,
|
|
180
143
|
launchAgentSession as launchAgentSessionImpl,
|
|
@@ -184,9 +147,7 @@ import {
|
|
|
184
147
|
import {
|
|
185
148
|
readWaveInfraGate as readWaveInfraGateImpl,
|
|
186
149
|
runClosureSweepPhase as runClosureSweepPhaseImpl,
|
|
187
|
-
} from "./
|
|
188
|
-
|
|
189
|
-
// --- Re-exports from launcher-gates.mjs ---
|
|
150
|
+
} from "./closure-engine.mjs";
|
|
190
151
|
import {
|
|
191
152
|
materializeAgentExecutionSummaryForRun,
|
|
192
153
|
readRunExecutionSummary,
|
|
@@ -207,71 +168,28 @@ import {
|
|
|
207
168
|
readWaveAssignmentBarrier,
|
|
208
169
|
readWaveDependencyBarrier,
|
|
209
170
|
buildGateSnapshot as buildGateSnapshotImpl,
|
|
210
|
-
} from "./
|
|
211
|
-
|
|
212
|
-
export {
|
|
213
|
-
readWaveContQaGate,
|
|
214
|
-
readWaveContEvalGate,
|
|
215
|
-
readWaveEvaluatorGate,
|
|
216
|
-
readWaveImplementationGate,
|
|
217
|
-
readWaveComponentGate,
|
|
218
|
-
readWaveComponentMatrixGate,
|
|
219
|
-
readWaveDocumentationGate,
|
|
220
|
-
readWaveSecurityGate,
|
|
221
|
-
readWaveIntegrationGate,
|
|
222
|
-
readWaveIntegrationBarrier,
|
|
223
|
-
readClarificationBarrier,
|
|
224
|
-
readWaveAssignmentBarrier,
|
|
225
|
-
readWaveDependencyBarrier,
|
|
226
|
-
};
|
|
227
|
-
|
|
228
|
-
// --- Re-exports from launcher-derived-state.mjs ---
|
|
171
|
+
} from "./gate-engine.mjs";
|
|
229
172
|
import {
|
|
230
173
|
waveAssignmentsPath,
|
|
231
174
|
waveDependencySnapshotPath,
|
|
232
|
-
|
|
175
|
+
buildWaveDerivedState,
|
|
233
176
|
applyDerivedStateToDashboard,
|
|
234
|
-
|
|
235
|
-
buildWaveIntegrationSummary,
|
|
236
|
-
} from "./launcher-derived-state.mjs";
|
|
237
|
-
|
|
238
|
-
export {
|
|
239
|
-
buildWaveSecuritySummary,
|
|
240
|
-
buildWaveIntegrationSummary,
|
|
241
|
-
};
|
|
242
|
-
|
|
243
|
-
// --- Re-exports from launcher-retry.mjs ---
|
|
177
|
+
} from "./derived-state-engine.mjs";
|
|
244
178
|
import {
|
|
245
|
-
buildResumePlan,
|
|
246
179
|
readWaveRelaunchPlan,
|
|
247
|
-
writeWaveRelaunchPlan,
|
|
248
180
|
clearWaveRelaunchPlan,
|
|
249
181
|
resetPersistedWaveLaunchState,
|
|
250
182
|
persistedRelaunchPlanMatchesCurrentState,
|
|
251
183
|
resolveSharedComponentContinuationRuns,
|
|
252
|
-
relaunchReasonBuckets,
|
|
253
184
|
applySharedComponentWaitStateToDashboard,
|
|
254
185
|
reconcileFailuresAgainstSharedComponentState,
|
|
255
186
|
hasReusableSuccessStatus,
|
|
256
187
|
selectReusablePreCompletedAgentIds,
|
|
257
188
|
selectInitialWaveRuns,
|
|
258
189
|
resolveRelaunchRuns,
|
|
259
|
-
applyPersistedRelaunchPlan,
|
|
260
190
|
executorFallbackChain,
|
|
261
191
|
preflightWavesForExecutorAvailability,
|
|
262
|
-
} from "./
|
|
263
|
-
|
|
264
|
-
export {
|
|
265
|
-
resetPersistedWaveLaunchState,
|
|
266
|
-
persistedRelaunchPlanMatchesCurrentState,
|
|
267
|
-
resolveSharedComponentContinuationRuns,
|
|
268
|
-
hasReusableSuccessStatus,
|
|
269
|
-
selectReusablePreCompletedAgentIds,
|
|
270
|
-
selectInitialWaveRuns,
|
|
271
|
-
resolveRelaunchRuns,
|
|
272
|
-
};
|
|
273
|
-
|
|
274
|
-
// --- Re-exports from launcher-supervisor.mjs ---
|
|
192
|
+
} from "./retry-engine.mjs";
|
|
275
193
|
import {
|
|
276
194
|
markLauncherFailed,
|
|
277
195
|
acquireLauncherLock,
|
|
@@ -286,50 +204,25 @@ import {
|
|
|
286
204
|
launchWaveDashboardSession,
|
|
287
205
|
cleanupLaneTmuxSessions,
|
|
288
206
|
pruneDryRunExecutorPreviewDirs,
|
|
207
|
+
recordAttemptState,
|
|
208
|
+
recordWaveRunState,
|
|
289
209
|
runTmux,
|
|
290
|
-
} from "./
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
.map((reason) => {
|
|
307
|
-
const code = compactSingleLine(reason?.code || "", 80);
|
|
308
|
-
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
309
|
-
return code && detail ? `${code}=${detail}` : "";
|
|
310
|
-
})
|
|
311
|
-
.filter(Boolean)
|
|
312
|
-
: [];
|
|
313
|
-
return `[reconcile] wave ${blockedWave?.wave ?? "unknown"} not reconstructable: ${
|
|
314
|
-
parts.join("; ") || "unknown reason"
|
|
315
|
-
}`;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
export function formatReconcilePreservedWaveLine(preservedWave) {
|
|
319
|
-
const parts = Array.isArray(preservedWave?.reasons)
|
|
320
|
-
? preservedWave.reasons
|
|
321
|
-
.map((reason) => {
|
|
322
|
-
const code = compactSingleLine(reason?.code || "", 80);
|
|
323
|
-
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
324
|
-
return code && detail ? `${code}=${detail}` : "";
|
|
325
|
-
})
|
|
326
|
-
.filter(Boolean)
|
|
327
|
-
: [];
|
|
328
|
-
const previousState = compactSingleLine(preservedWave?.previousState || "completed", 80);
|
|
329
|
-
return `[reconcile] wave ${preservedWave?.wave ?? "unknown"} preserved as ${previousState}: ${
|
|
330
|
-
parts.join("; ") || "unknown reason"
|
|
331
|
-
}`;
|
|
332
|
-
}
|
|
210
|
+
} from "./session-supervisor.mjs";
|
|
211
|
+
import {
|
|
212
|
+
planInitialWaveAttempt,
|
|
213
|
+
planRetryWaveAttempt,
|
|
214
|
+
} from "./implementation-engine.mjs";
|
|
215
|
+
import {
|
|
216
|
+
writeDashboardProjections,
|
|
217
|
+
writeWaveDerivedProjections,
|
|
218
|
+
writeWaveAttemptTraceProjection,
|
|
219
|
+
writeWaveRelaunchProjection,
|
|
220
|
+
} from "./projection-writer.mjs";
|
|
221
|
+
import {
|
|
222
|
+
formatReconcileBlockedWaveLine,
|
|
223
|
+
formatReconcilePreservedWaveLine,
|
|
224
|
+
} from "./reconcile-format.mjs";
|
|
225
|
+
import { computeReducerSnapshot } from "./reducer-snapshot.mjs";
|
|
333
226
|
|
|
334
227
|
function printUsage(lanePaths, terminalSurface) {
|
|
335
228
|
console.log(`Usage: pnpm exec wave launch [options]
|
|
@@ -548,9 +441,9 @@ function parseArgs(argv) {
|
|
|
548
441
|
return { help: false, lanePaths, options };
|
|
549
442
|
}
|
|
550
443
|
|
|
551
|
-
// ---
|
|
444
|
+
// --- Local wrappers that bind engine calls to launcher scope ---
|
|
552
445
|
|
|
553
|
-
|
|
446
|
+
async function runClosureSweepPhase({
|
|
554
447
|
lanePaths,
|
|
555
448
|
wave,
|
|
556
449
|
closureRuns,
|
|
@@ -590,17 +483,93 @@ export async function runClosureSweepPhase({
|
|
|
590
483
|
});
|
|
591
484
|
}
|
|
592
485
|
|
|
593
|
-
|
|
486
|
+
function readWaveInfraGate(agentRuns) {
|
|
594
487
|
return readWaveInfraGateImpl(agentRuns);
|
|
595
488
|
}
|
|
596
489
|
|
|
597
|
-
|
|
490
|
+
function buildGateSnapshot(params) {
|
|
598
491
|
return buildGateSnapshotImpl({
|
|
599
492
|
...params,
|
|
600
493
|
readWaveInfraGateFn: readWaveInfraGate,
|
|
601
494
|
});
|
|
602
495
|
}
|
|
603
496
|
|
|
497
|
+
function waveGateLabel(gateName) {
|
|
498
|
+
switch (gateName) {
|
|
499
|
+
case "implementationGate":
|
|
500
|
+
return "Implementation exit contract";
|
|
501
|
+
case "componentGate":
|
|
502
|
+
return "Component promotion";
|
|
503
|
+
case "helperAssignmentBarrier":
|
|
504
|
+
return "Helper assignment barrier";
|
|
505
|
+
case "dependencyBarrier":
|
|
506
|
+
return "Dependency barrier";
|
|
507
|
+
case "contEvalGate":
|
|
508
|
+
return "cont-EVAL";
|
|
509
|
+
case "securityGate":
|
|
510
|
+
return "Security review";
|
|
511
|
+
case "integrationBarrier":
|
|
512
|
+
return "Integration gate";
|
|
513
|
+
case "documentationGate":
|
|
514
|
+
return "Documentation closure";
|
|
515
|
+
case "componentMatrixGate":
|
|
516
|
+
return "Component matrix update";
|
|
517
|
+
case "contQaGate":
|
|
518
|
+
return "cont-QA gate";
|
|
519
|
+
case "infraGate":
|
|
520
|
+
return "Infra gate";
|
|
521
|
+
case "clarificationBarrier":
|
|
522
|
+
return "Clarification barrier";
|
|
523
|
+
default:
|
|
524
|
+
return "Wave gate";
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
function waveGateActionRequested(gateName, lanePaths) {
|
|
529
|
+
switch (gateName) {
|
|
530
|
+
case "implementationGate":
|
|
531
|
+
return `Lane ${lanePaths.lane} owners should resolve the implementation contract gap before wave progression.`;
|
|
532
|
+
case "componentGate":
|
|
533
|
+
return `Lane ${lanePaths.lane} owners should close the component promotion gap before wave progression.`;
|
|
534
|
+
case "helperAssignmentBarrier":
|
|
535
|
+
return `Lane ${lanePaths.lane} owners should resolve helper assignments before wave progression.`;
|
|
536
|
+
case "dependencyBarrier":
|
|
537
|
+
return `Lane ${lanePaths.lane} owners should resolve required dependencies before wave progression.`;
|
|
538
|
+
case "contEvalGate":
|
|
539
|
+
return `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`;
|
|
540
|
+
case "securityGate":
|
|
541
|
+
return `Lane ${lanePaths.lane} owners should resolve blocked security findings or missing approvals before integration closure.`;
|
|
542
|
+
case "integrationBarrier":
|
|
543
|
+
return `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`;
|
|
544
|
+
case "documentationGate":
|
|
545
|
+
return `Lane ${lanePaths.lane} owners should resolve the shared-plan closure state before wave progression.`;
|
|
546
|
+
case "componentMatrixGate":
|
|
547
|
+
return `Lane ${lanePaths.lane} owners should update the component cutover matrix current levels before wave progression.`;
|
|
548
|
+
case "contQaGate":
|
|
549
|
+
return `Lane ${lanePaths.lane} owners should resolve the cont-QA gate before wave progression.`;
|
|
550
|
+
case "infraGate":
|
|
551
|
+
return `Lane ${lanePaths.lane} owners should resolve the infra gate before wave progression.`;
|
|
552
|
+
case "clarificationBarrier":
|
|
553
|
+
return `Lane ${lanePaths.lane} owners should resolve open clarification chains before wave progression.`;
|
|
554
|
+
default:
|
|
555
|
+
return `Lane ${lanePaths.lane} owners should resolve the failing gate before wave progression.`;
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function buildFailureFromGate(gateName, gate, fallbackLogPath) {
|
|
560
|
+
return {
|
|
561
|
+
agentId: gate?.agentId || null,
|
|
562
|
+
statusCode: gate?.statusCode || gateName,
|
|
563
|
+
logPath: gate?.logPath || fallbackLogPath,
|
|
564
|
+
detail: gate?.detail || null,
|
|
565
|
+
componentId: gate?.componentId || null,
|
|
566
|
+
ownerAgentIds: gate?.ownerAgentIds || [],
|
|
567
|
+
satisfiedAgentIds: gate?.satisfiedAgentIds || [],
|
|
568
|
+
waitingOnAgentIds: gate?.waitingOnAgentIds || [],
|
|
569
|
+
failedOwnContractAgentIds: gate?.failedOwnContractAgentIds || [],
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
|
|
604
573
|
// --- Main entry point ---
|
|
605
574
|
|
|
606
575
|
export async function runLauncherCli(argv) {
|
|
@@ -699,16 +668,17 @@ export async function runLauncherCli(argv) {
|
|
|
699
668
|
}),
|
|
700
669
|
)
|
|
701
670
|
.map((wave) =>
|
|
702
|
-
|
|
703
|
-
|
|
671
|
+
{
|
|
672
|
+
const waveWithContext7 = applyContext7SelectionsToWave(wave, {
|
|
704
673
|
lane: lanePaths.lane,
|
|
705
674
|
bundleIndex: context7BundleIndex,
|
|
706
|
-
})
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
675
|
+
});
|
|
676
|
+
return {
|
|
677
|
+
...waveWithContext7,
|
|
678
|
+
lane: lanePaths.lane,
|
|
679
|
+
...resolveWaveRoleBindings(waveWithContext7, lanePaths, waveWithContext7.agents),
|
|
680
|
+
};
|
|
681
|
+
},
|
|
712
682
|
)
|
|
713
683
|
.map((wave) => validateWaveDefinition(wave, { laneProfile: lanePaths.laneProfile }));
|
|
714
684
|
const reconciliation = reconcileRunStateFromStatusFiles(
|
|
@@ -823,7 +793,7 @@ export async function runLauncherCli(argv) {
|
|
|
823
793
|
if (options.dryRun) {
|
|
824
794
|
pruneDryRunExecutorPreviewDirs(lanePaths, allWaves);
|
|
825
795
|
for (const wave of filteredWaves) {
|
|
826
|
-
const derivedState =
|
|
796
|
+
const derivedState = buildWaveDerivedState({
|
|
827
797
|
lanePaths,
|
|
828
798
|
wave,
|
|
829
799
|
summariesByAgentId: {},
|
|
@@ -831,10 +801,14 @@ export async function runLauncherCli(argv) {
|
|
|
831
801
|
attempt: 0,
|
|
832
802
|
orchestratorId: options.orchestratorId,
|
|
833
803
|
});
|
|
804
|
+
writeWaveDerivedProjections({ lanePaths, wave, derivedState });
|
|
834
805
|
const agentRuns = wave.agents.map((agent) => {
|
|
835
806
|
const safeName = `wave-${wave.wave}-${agent.slug}`;
|
|
836
807
|
return {
|
|
837
808
|
agent,
|
|
809
|
+
lane: lanePaths.lane,
|
|
810
|
+
wave: wave.wave,
|
|
811
|
+
resultsDir: lanePaths.resultsDir,
|
|
838
812
|
sessionName: `dry-run-wave-${wave.wave}-${agent.slug}`,
|
|
839
813
|
promptPath: path.join(lanePaths.promptsDir, `${safeName}.prompt.md`),
|
|
840
814
|
logPath: path.join(lanePaths.logsDir, `${safeName}.log`),
|
|
@@ -892,7 +866,7 @@ export async function runLauncherCli(argv) {
|
|
|
892
866
|
manifestOut: options.manifestOut,
|
|
893
867
|
feedbackRequestsDir: lanePaths.feedbackRequestsDir,
|
|
894
868
|
});
|
|
895
|
-
|
|
869
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
896
870
|
|
|
897
871
|
if (terminalRegistryEnabled && !options.keepTerminals) {
|
|
898
872
|
const removed = removeLaneTemporaryTerminalEntries(lanePaths.terminalsPath, lanePaths);
|
|
@@ -911,7 +885,7 @@ export async function runLauncherCli(argv) {
|
|
|
911
885
|
});
|
|
912
886
|
}
|
|
913
887
|
}
|
|
914
|
-
|
|
888
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
915
889
|
|
|
916
890
|
if (options.dashboard) {
|
|
917
891
|
globalDashboardTerminalEntry = createGlobalDashboardTerminalEntry(
|
|
@@ -955,10 +929,10 @@ export async function runLauncherCli(argv) {
|
|
|
955
929
|
status: "running",
|
|
956
930
|
details: `agents=${wave.agents.map((agent) => agent.agentId).join(", ")}; wave_file=${wave.file}`,
|
|
957
931
|
});
|
|
958
|
-
|
|
932
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
959
933
|
|
|
960
934
|
const runTag = crypto.randomBytes(3).toString("hex");
|
|
961
|
-
let derivedState =
|
|
935
|
+
let derivedState = buildWaveDerivedState({
|
|
962
936
|
lanePaths,
|
|
963
937
|
wave,
|
|
964
938
|
summariesByAgentId: {},
|
|
@@ -966,6 +940,7 @@ export async function runLauncherCli(argv) {
|
|
|
966
940
|
attempt: 0,
|
|
967
941
|
orchestratorId: options.orchestratorId,
|
|
968
942
|
});
|
|
943
|
+
writeWaveDerivedProjections({ lanePaths, wave, derivedState });
|
|
969
944
|
const messageBoardPath = derivedState.messageBoardPath;
|
|
970
945
|
console.log(`Wave message board: ${path.relative(REPO_ROOT, messageBoardPath)}`);
|
|
971
946
|
|
|
@@ -977,12 +952,15 @@ export async function runLauncherCli(argv) {
|
|
|
977
952
|
const residentOrchestratorState = { closed: false };
|
|
978
953
|
|
|
979
954
|
const flushDashboards = () => {
|
|
980
|
-
if (!dashboardState) {
|
|
955
|
+
if (!dashboardState && !globalDashboard) {
|
|
981
956
|
return;
|
|
982
957
|
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
958
|
+
writeDashboardProjections({
|
|
959
|
+
lanePaths,
|
|
960
|
+
globalDashboard,
|
|
961
|
+
dashboardState,
|
|
962
|
+
dashboardPath,
|
|
963
|
+
});
|
|
986
964
|
};
|
|
987
965
|
|
|
988
966
|
const recordCombinedEvent = ({ level = "info", agentId = null, message }) => {
|
|
@@ -1030,6 +1008,9 @@ export async function runLauncherCli(argv) {
|
|
|
1030
1008
|
}
|
|
1031
1009
|
return {
|
|
1032
1010
|
agent,
|
|
1011
|
+
lane: lanePaths.lane,
|
|
1012
|
+
wave: wave.wave,
|
|
1013
|
+
resultsDir: lanePaths.resultsDir,
|
|
1033
1014
|
sessionName,
|
|
1034
1015
|
promptPath: path.join(lanePaths.promptsDir, `${safeName}.prompt.md`),
|
|
1035
1016
|
logPath: path.join(lanePaths.logsDir, `${safeName}.log`),
|
|
@@ -1048,6 +1029,7 @@ export async function runLauncherCli(argv) {
|
|
|
1048
1029
|
inboxText: derivedState.inboxesByAgentId[agent.agentId]?.text || "",
|
|
1049
1030
|
};
|
|
1050
1031
|
});
|
|
1032
|
+
const roleBindings = resolveWaveRoleBindings(wave, lanePaths, wave.agents);
|
|
1051
1033
|
|
|
1052
1034
|
const refreshDerivedState = (attemptNumber = 0) => {
|
|
1053
1035
|
const proofRegistry = readWaveProofRegistry(lanePaths, wave.wave);
|
|
@@ -1066,7 +1048,7 @@ export async function runLauncherCli(argv) {
|
|
|
1066
1048
|
agentIds: agentRuns.map((run) => run.agent.agentId),
|
|
1067
1049
|
orchestratorId: options.orchestratorId,
|
|
1068
1050
|
});
|
|
1069
|
-
derivedState =
|
|
1051
|
+
derivedState = buildWaveDerivedState({
|
|
1070
1052
|
lanePaths,
|
|
1071
1053
|
wave,
|
|
1072
1054
|
agentRuns,
|
|
@@ -1075,6 +1057,7 @@ export async function runLauncherCli(argv) {
|
|
|
1075
1057
|
attempt: attemptNumber,
|
|
1076
1058
|
orchestratorId: options.orchestratorId,
|
|
1077
1059
|
});
|
|
1060
|
+
writeWaveDerivedProjections({ lanePaths, wave, derivedState });
|
|
1078
1061
|
const controlPlaneLogPath = path.join(
|
|
1079
1062
|
lanePaths.controlPlaneDir,
|
|
1080
1063
|
`wave-${wave.wave}.jsonl`,
|
|
@@ -1098,6 +1081,20 @@ export async function runLauncherCli(argv) {
|
|
|
1098
1081
|
return derivedState;
|
|
1099
1082
|
};
|
|
1100
1083
|
|
|
1084
|
+
let latestReducerSnapshot = null;
|
|
1085
|
+
const refreshReducerSnapshot = (attemptNumber = 0, extra = {}) => {
|
|
1086
|
+
latestReducerSnapshot = computeReducerSnapshot({
|
|
1087
|
+
lanePaths,
|
|
1088
|
+
wave,
|
|
1089
|
+
agentRuns,
|
|
1090
|
+
derivedState,
|
|
1091
|
+
attempt: attemptNumber,
|
|
1092
|
+
options,
|
|
1093
|
+
...extra,
|
|
1094
|
+
});
|
|
1095
|
+
return latestReducerSnapshot;
|
|
1096
|
+
};
|
|
1097
|
+
|
|
1101
1098
|
refreshDerivedState(0);
|
|
1102
1099
|
const launchStateReset = resetPersistedWaveLaunchState(lanePaths, wave.wave, options);
|
|
1103
1100
|
if (launchStateReset.clearedRelaunchPlan) {
|
|
@@ -1187,12 +1184,16 @@ export async function runLauncherCli(argv) {
|
|
|
1187
1184
|
};
|
|
1188
1185
|
|
|
1189
1186
|
const proofRegistryForReuse = readWaveProofRegistry(lanePaths, wave.wave);
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1187
|
+
const initialAttemptPlan = planInitialWaveAttempt({
|
|
1188
|
+
agentRuns,
|
|
1189
|
+
lanePaths,
|
|
1192
1190
|
wave,
|
|
1193
1191
|
derivedState,
|
|
1194
1192
|
proofRegistry: proofRegistryForReuse,
|
|
1193
|
+
retryOverride,
|
|
1194
|
+
persistedRelaunchPlan,
|
|
1195
1195
|
});
|
|
1196
|
+
const preCompletedAgentIds = initialAttemptPlan.preCompletedAgentIds;
|
|
1196
1197
|
for (const agentId of preCompletedAgentIds) {
|
|
1197
1198
|
setWaveDashboardAgent(dashboardState, agentId, {
|
|
1198
1199
|
state: "completed",
|
|
@@ -1201,13 +1202,7 @@ export async function runLauncherCli(argv) {
|
|
|
1201
1202
|
detail: "Pre-existing status=0",
|
|
1202
1203
|
});
|
|
1203
1204
|
}
|
|
1204
|
-
const staleCompletedAgentIds =
|
|
1205
|
-
.filter(
|
|
1206
|
-
(run) =>
|
|
1207
|
-
!preCompletedAgentIds.has(run.agent.agentId) &&
|
|
1208
|
-
readStatusCodeIfPresent(run.statusPath) === 0,
|
|
1209
|
-
)
|
|
1210
|
-
.map((run) => run.agent.agentId);
|
|
1205
|
+
const staleCompletedAgentIds = initialAttemptPlan.staleCompletedAgentIds;
|
|
1211
1206
|
for (const agentId of staleCompletedAgentIds) {
|
|
1212
1207
|
setWaveDashboardAgent(dashboardState, agentId, {
|
|
1213
1208
|
state: "pending",
|
|
@@ -1283,26 +1278,11 @@ export async function runLauncherCli(argv) {
|
|
|
1283
1278
|
}
|
|
1284
1279
|
}
|
|
1285
1280
|
|
|
1286
|
-
|
|
1287
|
-
if (
|
|
1288
|
-
persistedRelaunchPlan &&
|
|
1289
|
-
!persistedRelaunchPlanMatchesCurrentState(
|
|
1290
|
-
agentRuns,
|
|
1291
|
-
persistedRelaunchPlan,
|
|
1292
|
-
lanePaths,
|
|
1293
|
-
wave,
|
|
1294
|
-
)
|
|
1295
|
-
) {
|
|
1281
|
+
if (initialAttemptPlan.shouldClearPersistedRelaunchPlan) {
|
|
1296
1282
|
clearWaveRelaunchPlan(lanePaths, wave.wave);
|
|
1297
1283
|
persistedRelaunchPlan = null;
|
|
1298
1284
|
}
|
|
1299
|
-
const
|
|
1300
|
-
availableRuns,
|
|
1301
|
-
persistedRelaunchPlan,
|
|
1302
|
-
lanePaths,
|
|
1303
|
-
wave,
|
|
1304
|
-
);
|
|
1305
|
-
const overrideRuns = resolveRetryOverrideRuns(availableRuns, retryOverride, lanePaths, wave);
|
|
1285
|
+
const overrideRuns = initialAttemptPlan.overrideResolution;
|
|
1306
1286
|
if (overrideRuns.unknownAgentIds.length > 0) {
|
|
1307
1287
|
appendCoordination({
|
|
1308
1288
|
event: "retry_override_invalid",
|
|
@@ -1315,13 +1295,8 @@ export async function runLauncherCli(argv) {
|
|
|
1315
1295
|
clearWaveRetryOverride(lanePaths, wave.wave);
|
|
1316
1296
|
retryOverride = null;
|
|
1317
1297
|
}
|
|
1318
|
-
let runsToLaunch =
|
|
1319
|
-
|
|
1320
|
-
? overrideRuns.runs
|
|
1321
|
-
: persistedRuns.length > 0
|
|
1322
|
-
? persistedRuns
|
|
1323
|
-
: selectInitialWaveRuns(availableRuns, lanePaths);
|
|
1324
|
-
if (overrideRuns.runs.length > 0) {
|
|
1298
|
+
let runsToLaunch = initialAttemptPlan.selectedRuns;
|
|
1299
|
+
if (initialAttemptPlan.source === "override" && overrideRuns.runs.length > 0) {
|
|
1325
1300
|
appendCoordination({
|
|
1326
1301
|
event: "retry_override_applied",
|
|
1327
1302
|
waves: [wave.wave],
|
|
@@ -1338,35 +1313,9 @@ export async function runLauncherCli(argv) {
|
|
|
1338
1313
|
let traceAttempt = 1;
|
|
1339
1314
|
let completionGateSnapshot = null;
|
|
1340
1315
|
let completionTraceDir = null;
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
entityId: `wave-${wave.wave}-attempt-${attemptNumber}`,
|
|
1345
|
-
action: state,
|
|
1346
|
-
source: "launcher",
|
|
1347
|
-
actor: "launcher",
|
|
1348
|
-
data: {
|
|
1349
|
-
attemptId: `wave-${wave.wave}-attempt-${attemptNumber}`,
|
|
1350
|
-
attemptNumber,
|
|
1351
|
-
state,
|
|
1352
|
-
selectedAgentIds: data.selectedAgentIds || [],
|
|
1353
|
-
detail: data.detail || null,
|
|
1354
|
-
updatedAt: toIsoTimestamp(),
|
|
1355
|
-
...(data.createdAt ? { createdAt: data.createdAt } : {}),
|
|
1356
|
-
},
|
|
1357
|
-
});
|
|
1358
|
-
appendWaveControlEvent(lanePaths, wave.wave, {
|
|
1359
|
-
entityType: "wave_run",
|
|
1360
|
-
entityId: `wave-${wave.wave}`,
|
|
1361
|
-
action: "started",
|
|
1362
|
-
source: "launcher",
|
|
1363
|
-
actor: "launcher",
|
|
1364
|
-
data: {
|
|
1365
|
-
waveId: `wave-${wave.wave}`,
|
|
1366
|
-
waveNumber: wave.wave,
|
|
1367
|
-
agentIds: wave.agents.map((agent) => agent.agentId),
|
|
1368
|
-
runVariant: lanePaths.runVariant || "live",
|
|
1369
|
-
},
|
|
1316
|
+
recordWaveRunState(lanePaths, wave.wave, "started", {
|
|
1317
|
+
agentIds: wave.agents.map((agent) => agent.agentId),
|
|
1318
|
+
runVariant: lanePaths.runVariant || "live",
|
|
1370
1319
|
});
|
|
1371
1320
|
|
|
1372
1321
|
while (attempt <= options.maxRetriesPerWave + 1) {
|
|
@@ -1379,36 +1328,19 @@ export async function runLauncherCli(argv) {
|
|
|
1379
1328
|
recordCombinedEvent({
|
|
1380
1329
|
message: `Attempt ${attempt}/${options.maxRetriesPerWave + 1}; launching agents: ${runsToLaunch.map((run) => run.agent.agentId).join(", ") || "none"}`,
|
|
1381
1330
|
});
|
|
1382
|
-
recordAttemptState(attempt, "running", {
|
|
1331
|
+
recordAttemptState(lanePaths, wave.wave, attempt, "running", {
|
|
1383
1332
|
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
1384
1333
|
detail: `Launching ${runsToLaunch.map((run) => run.agent.agentId).join(", ") || "no"} agents.`,
|
|
1385
1334
|
createdAt: toIsoTimestamp(),
|
|
1386
1335
|
});
|
|
1387
1336
|
|
|
1388
1337
|
const launchedImplementationRuns = runsToLaunch.filter(
|
|
1389
|
-
(run) =>
|
|
1390
|
-
![
|
|
1391
|
-
lanePaths.contEvalAgentId,
|
|
1392
|
-
lanePaths.contQaAgentId,
|
|
1393
|
-
lanePaths.integrationAgentId,
|
|
1394
|
-
lanePaths.documentationAgentId,
|
|
1395
|
-
].includes(
|
|
1396
|
-
run.agent.agentId,
|
|
1397
|
-
),
|
|
1338
|
+
(run) => !isClosureRoleAgentId(run.agent.agentId, roleBindings),
|
|
1398
1339
|
);
|
|
1399
1340
|
const closureOnlyRetry =
|
|
1400
1341
|
runsToLaunch.length > 0 &&
|
|
1401
1342
|
launchedImplementationRuns.length === 0 &&
|
|
1402
|
-
runsToLaunch.every((run) =>
|
|
1403
|
-
[
|
|
1404
|
-
lanePaths.contEvalAgentId,
|
|
1405
|
-
lanePaths.contQaAgentId,
|
|
1406
|
-
lanePaths.integrationAgentId,
|
|
1407
|
-
lanePaths.documentationAgentId,
|
|
1408
|
-
].includes(
|
|
1409
|
-
run.agent.agentId,
|
|
1410
|
-
),
|
|
1411
|
-
);
|
|
1343
|
+
runsToLaunch.every((run) => isClosureRoleAgentId(run.agent.agentId, roleBindings));
|
|
1412
1344
|
|
|
1413
1345
|
let failures = [];
|
|
1414
1346
|
let timedOut = false;
|
|
@@ -1463,6 +1395,11 @@ export async function runLauncherCli(argv) {
|
|
|
1463
1395
|
agentRateLimitBaseDelaySeconds: options.agentRateLimitBaseDelaySeconds,
|
|
1464
1396
|
agentRateLimitMaxDelaySeconds: options.agentRateLimitMaxDelaySeconds,
|
|
1465
1397
|
context7Enabled: options.context7Enabled,
|
|
1398
|
+
attempt,
|
|
1399
|
+
controlPlane: {
|
|
1400
|
+
waveNumber: wave.wave,
|
|
1401
|
+
attempt,
|
|
1402
|
+
},
|
|
1466
1403
|
});
|
|
1467
1404
|
runInfo.lastLaunchAttempt = attempt;
|
|
1468
1405
|
runInfo.lastPromptHash = launchResult?.promptHash || null;
|
|
@@ -1474,23 +1411,6 @@ export async function runLauncherCli(argv) {
|
|
|
1474
1411
|
state: "running",
|
|
1475
1412
|
detail: "Session launched",
|
|
1476
1413
|
});
|
|
1477
|
-
appendWaveControlEvent(lanePaths, wave.wave, {
|
|
1478
|
-
entityType: "agent_run",
|
|
1479
|
-
entityId: `wave-${wave.wave}-attempt-${attempt}-agent-${runInfo.agent.agentId}`,
|
|
1480
|
-
action: "started",
|
|
1481
|
-
source: "launcher",
|
|
1482
|
-
actor: runInfo.agent.agentId,
|
|
1483
|
-
attempt,
|
|
1484
|
-
data: {
|
|
1485
|
-
agentId: runInfo.agent.agentId,
|
|
1486
|
-
attemptNumber: attempt,
|
|
1487
|
-
sessionName: runInfo.sessionName,
|
|
1488
|
-
executorId: runInfo.lastExecutorId,
|
|
1489
|
-
promptPath: path.relative(REPO_ROOT, runInfo.promptPath),
|
|
1490
|
-
statusPath: path.relative(REPO_ROOT, runInfo.statusPath),
|
|
1491
|
-
logPath: path.relative(REPO_ROOT, runInfo.logPath),
|
|
1492
|
-
},
|
|
1493
|
-
});
|
|
1494
1414
|
recordCombinedEvent({
|
|
1495
1415
|
agentId: runInfo.agent.agentId,
|
|
1496
1416
|
message: `Launched in tmux session ${runInfo.sessionName}`,
|
|
@@ -1551,34 +1471,18 @@ export async function runLauncherCli(argv) {
|
|
|
1551
1471
|
flushDashboards();
|
|
1552
1472
|
}
|
|
1553
1473
|
},
|
|
1474
|
+
{
|
|
1475
|
+
controlPlane: {
|
|
1476
|
+
waveNumber: wave.wave,
|
|
1477
|
+
attempt,
|
|
1478
|
+
},
|
|
1479
|
+
},
|
|
1554
1480
|
);
|
|
1555
1481
|
failures = waitResult.failures;
|
|
1556
1482
|
timedOut = waitResult.timedOut;
|
|
1557
1483
|
}
|
|
1558
1484
|
|
|
1559
1485
|
materializeAgentExecutionSummaries(wave, agentRuns);
|
|
1560
|
-
for (const runInfo of runsToLaunch) {
|
|
1561
|
-
const statusRecord = readStatusRecordIfPresent(runInfo.statusPath);
|
|
1562
|
-
const action = Number(statusRecord?.code) === 0 ? "completed" : "failed";
|
|
1563
|
-
appendWaveControlEvent(lanePaths, wave.wave, {
|
|
1564
|
-
entityType: "agent_run",
|
|
1565
|
-
entityId: `wave-${wave.wave}-attempt-${attempt}-agent-${runInfo.agent.agentId}`,
|
|
1566
|
-
action,
|
|
1567
|
-
source: "launcher",
|
|
1568
|
-
actor: runInfo.agent.agentId,
|
|
1569
|
-
attempt,
|
|
1570
|
-
data: {
|
|
1571
|
-
agentId: runInfo.agent.agentId,
|
|
1572
|
-
attemptNumber: attempt,
|
|
1573
|
-
exitCode: statusRecord?.code ?? null,
|
|
1574
|
-
completedAt: statusRecord?.completedAt || null,
|
|
1575
|
-
promptHash: statusRecord?.promptHash || runInfo.lastPromptHash || null,
|
|
1576
|
-
executorId: runInfo.lastExecutorId || null,
|
|
1577
|
-
logPath: path.relative(REPO_ROOT, runInfo.logPath),
|
|
1578
|
-
statusPath: path.relative(REPO_ROOT, runInfo.statusPath),
|
|
1579
|
-
},
|
|
1580
|
-
});
|
|
1581
|
-
}
|
|
1582
1486
|
refreshDerivedState(attempt);
|
|
1583
1487
|
lastLiveCoordinationRefreshAt = Date.now();
|
|
1584
1488
|
emitCoordinationAlertEvents(derivedState);
|
|
@@ -1627,6 +1531,7 @@ export async function runLauncherCli(argv) {
|
|
|
1627
1531
|
} else {
|
|
1628
1532
|
const componentGate = readWaveComponentGate(wave, agentRuns, {
|
|
1629
1533
|
laneProfile: lanePaths.laneProfile,
|
|
1534
|
+
mode: "live",
|
|
1630
1535
|
});
|
|
1631
1536
|
if (!componentGate.ok) {
|
|
1632
1537
|
if (componentGate.statusCode === "shared-component-sibling-pending") {
|
|
@@ -1658,8 +1563,13 @@ export async function runLauncherCli(argv) {
|
|
|
1658
1563
|
actionRequested: `Lane ${lanePaths.lane} owners should close the component promotion gap before wave progression.`,
|
|
1659
1564
|
});
|
|
1660
1565
|
} else if (launchedImplementationRuns.length > 0) {
|
|
1661
|
-
const
|
|
1662
|
-
const
|
|
1566
|
+
const reducerDecision = refreshReducerSnapshot(attempt);
|
|
1567
|
+
const helperAssignmentBarrier =
|
|
1568
|
+
reducerDecision?.reducerState?.gateSnapshot?.helperAssignmentBarrier ||
|
|
1569
|
+
readWaveAssignmentBarrier(derivedState);
|
|
1570
|
+
const dependencyBarrier =
|
|
1571
|
+
reducerDecision?.reducerState?.gateSnapshot?.dependencyBarrier ||
|
|
1572
|
+
readWaveDependencyBarrier(derivedState);
|
|
1663
1573
|
if (!helperAssignmentBarrier.ok) {
|
|
1664
1574
|
failures = [
|
|
1665
1575
|
{
|
|
@@ -1708,14 +1618,7 @@ export async function runLauncherCli(argv) {
|
|
|
1708
1618
|
lanePaths,
|
|
1709
1619
|
wave,
|
|
1710
1620
|
closureRuns: agentRuns.filter((run) =>
|
|
1711
|
-
|
|
1712
|
-
lanePaths.contEvalAgentId,
|
|
1713
|
-
lanePaths.contQaAgentId,
|
|
1714
|
-
lanePaths.integrationAgentId,
|
|
1715
|
-
lanePaths.documentationAgentId,
|
|
1716
|
-
].includes(
|
|
1717
|
-
run.agent.agentId,
|
|
1718
|
-
),
|
|
1621
|
+
isClosureRoleAgentId(run.agent.agentId, roleBindings),
|
|
1719
1622
|
),
|
|
1720
1623
|
coordinationLogPath: derivedState.coordinationLogPath,
|
|
1721
1624
|
refreshDerivedState,
|
|
@@ -1740,7 +1643,10 @@ export async function runLauncherCli(argv) {
|
|
|
1740
1643
|
}
|
|
1741
1644
|
|
|
1742
1645
|
if (failures.length === 0) {
|
|
1743
|
-
const
|
|
1646
|
+
const reducerDecision = refreshReducerSnapshot(attempt);
|
|
1647
|
+
const helperAssignmentBarrier =
|
|
1648
|
+
reducerDecision?.reducerState?.gateSnapshot?.helperAssignmentBarrier ||
|
|
1649
|
+
readWaveAssignmentBarrier(derivedState);
|
|
1744
1650
|
if (!helperAssignmentBarrier.ok) {
|
|
1745
1651
|
failures = [
|
|
1746
1652
|
{
|
|
@@ -1765,7 +1671,10 @@ export async function runLauncherCli(argv) {
|
|
|
1765
1671
|
}
|
|
1766
1672
|
|
|
1767
1673
|
if (failures.length === 0) {
|
|
1768
|
-
const
|
|
1674
|
+
const reducerDecision = refreshReducerSnapshot(attempt);
|
|
1675
|
+
const dependencyBarrier =
|
|
1676
|
+
reducerDecision?.reducerState?.gateSnapshot?.dependencyBarrier ||
|
|
1677
|
+
readWaveDependencyBarrier(derivedState);
|
|
1769
1678
|
if (!dependencyBarrier.ok) {
|
|
1770
1679
|
failures = [
|
|
1771
1680
|
{
|
|
@@ -1790,140 +1699,44 @@ export async function runLauncherCli(argv) {
|
|
|
1790
1699
|
}
|
|
1791
1700
|
|
|
1792
1701
|
if (failures.length === 0) {
|
|
1793
|
-
const
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
message: `cont-EVAL blocked wave ${wave.wave}: ${contEvalGate.detail}`,
|
|
1811
|
-
});
|
|
1812
|
-
appendCoordination({
|
|
1813
|
-
event: "wave_gate_blocked",
|
|
1814
|
-
waves: [wave.wave],
|
|
1815
|
-
status: "blocked",
|
|
1816
|
-
details: `agent=${contEvalGate.agentId}; reason=${contEvalGate.statusCode}; ${contEvalGate.detail}`,
|
|
1817
|
-
actionRequested: `Lane ${lanePaths.lane} owners should resolve cont-EVAL tuning gaps before integration closure.`,
|
|
1818
|
-
});
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
|
-
if (failures.length === 0) {
|
|
1823
|
-
const integrationGate = readWaveIntegrationGate(wave, agentRuns, {
|
|
1824
|
-
integrationAgentId: lanePaths.integrationAgentId,
|
|
1825
|
-
requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
|
|
1826
|
-
});
|
|
1827
|
-
if (!integrationGate.ok) {
|
|
1828
|
-
failures = [
|
|
1829
|
-
{
|
|
1830
|
-
agentId: integrationGate.agentId,
|
|
1831
|
-
statusCode: integrationGate.statusCode,
|
|
1832
|
-
logPath: integrationGate.logPath || path.relative(REPO_ROOT, messageBoardPath),
|
|
1833
|
-
},
|
|
1834
|
-
];
|
|
1835
|
-
recordCombinedEvent({
|
|
1836
|
-
level: "error",
|
|
1837
|
-
agentId: integrationGate.agentId,
|
|
1838
|
-
message: `Integration gate blocked wave ${wave.wave}: ${integrationGate.detail}`,
|
|
1839
|
-
});
|
|
1840
|
-
appendCoordination({
|
|
1841
|
-
event: "wave_gate_blocked",
|
|
1842
|
-
waves: [wave.wave],
|
|
1843
|
-
status: "blocked",
|
|
1844
|
-
details: `agent=${integrationGate.agentId}; reason=${integrationGate.statusCode}; ${integrationGate.detail}`,
|
|
1845
|
-
actionRequested: `Lane ${lanePaths.lane} owners should resolve integration contradictions or blockers before documentation and cont-QA closure.`,
|
|
1846
|
-
});
|
|
1847
|
-
}
|
|
1848
|
-
}
|
|
1849
|
-
|
|
1850
|
-
if (failures.length === 0) {
|
|
1851
|
-
const documentationGate = readWaveDocumentationGate(wave, agentRuns);
|
|
1852
|
-
if (!documentationGate.ok) {
|
|
1853
|
-
failures = [
|
|
1854
|
-
{
|
|
1855
|
-
agentId: documentationGate.agentId,
|
|
1856
|
-
statusCode: documentationGate.statusCode,
|
|
1857
|
-
logPath: documentationGate.logPath || path.relative(REPO_ROOT, messageBoardPath),
|
|
1858
|
-
},
|
|
1859
|
-
];
|
|
1860
|
-
recordCombinedEvent({
|
|
1861
|
-
level: "error",
|
|
1862
|
-
agentId: documentationGate.agentId,
|
|
1863
|
-
message: `Documentation closure blocked wave ${wave.wave}: ${documentationGate.detail}`,
|
|
1864
|
-
});
|
|
1865
|
-
appendCoordination({
|
|
1866
|
-
event: "wave_gate_blocked",
|
|
1867
|
-
waves: [wave.wave],
|
|
1868
|
-
status: "blocked",
|
|
1869
|
-
details: `agent=${documentationGate.agentId}; reason=${documentationGate.statusCode}; ${documentationGate.detail}`,
|
|
1870
|
-
actionRequested: `Lane ${lanePaths.lane} owners should resolve the shared-plan closure state before wave progression.`,
|
|
1871
|
-
});
|
|
1872
|
-
}
|
|
1873
|
-
}
|
|
1874
|
-
|
|
1875
|
-
if (failures.length === 0) {
|
|
1876
|
-
const componentMatrixGate = readWaveComponentMatrixGate(wave, agentRuns, {
|
|
1877
|
-
laneProfile: lanePaths.laneProfile,
|
|
1878
|
-
documentationAgentId: lanePaths.documentationAgentId,
|
|
1879
|
-
});
|
|
1880
|
-
if (!componentMatrixGate.ok) {
|
|
1881
|
-
failures = [
|
|
1882
|
-
{
|
|
1883
|
-
agentId: componentMatrixGate.agentId,
|
|
1884
|
-
statusCode: componentMatrixGate.statusCode,
|
|
1885
|
-
logPath:
|
|
1886
|
-
componentMatrixGate.logPath || path.relative(REPO_ROOT, messageBoardPath),
|
|
1887
|
-
},
|
|
1888
|
-
];
|
|
1889
|
-
recordCombinedEvent({
|
|
1890
|
-
level: "error",
|
|
1891
|
-
agentId: componentMatrixGate.agentId,
|
|
1892
|
-
message: `Component matrix update blocked wave ${wave.wave}: ${componentMatrixGate.detail}`,
|
|
1893
|
-
});
|
|
1894
|
-
appendCoordination({
|
|
1895
|
-
event: "wave_gate_blocked",
|
|
1896
|
-
waves: [wave.wave],
|
|
1897
|
-
status: "blocked",
|
|
1898
|
-
details: `component=${componentMatrixGate.componentId || "unknown"}; reason=${componentMatrixGate.statusCode}; ${componentMatrixGate.detail}`,
|
|
1899
|
-
actionRequested: `Lane ${lanePaths.lane} owners should update the component cutover matrix current levels before wave progression.`,
|
|
1900
|
-
});
|
|
1901
|
-
}
|
|
1902
|
-
}
|
|
1903
|
-
|
|
1904
|
-
if (failures.length === 0) {
|
|
1905
|
-
const contQaGate = readWaveContQaGate(wave, agentRuns, { mode: "live" });
|
|
1906
|
-
if (!contQaGate.ok) {
|
|
1702
|
+
const reducerDecision = refreshReducerSnapshot(attempt);
|
|
1703
|
+
const authoritativeGateSnapshot = reducerDecision?.reducerState?.gateSnapshot;
|
|
1704
|
+
completionGateSnapshot = authoritativeGateSnapshot;
|
|
1705
|
+
const failingGateName = authoritativeGateSnapshot?.overall?.ok === false
|
|
1706
|
+
? authoritativeGateSnapshot.overall.gate
|
|
1707
|
+
: null;
|
|
1708
|
+
const failingGate =
|
|
1709
|
+
failingGateName && authoritativeGateSnapshot
|
|
1710
|
+
? authoritativeGateSnapshot[failingGateName]
|
|
1711
|
+
: null;
|
|
1712
|
+
if (failingGateName && failingGate) {
|
|
1713
|
+
if (
|
|
1714
|
+
failingGateName === "componentGate" &&
|
|
1715
|
+
failingGate.statusCode === "shared-component-sibling-pending"
|
|
1716
|
+
) {
|
|
1717
|
+
applySharedComponentWaitStateToDashboard(failingGate, dashboardState);
|
|
1718
|
+
}
|
|
1907
1719
|
failures = [
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1720
|
+
buildFailureFromGate(
|
|
1721
|
+
failingGateName,
|
|
1722
|
+
failingGate,
|
|
1723
|
+
path.relative(REPO_ROOT, messageBoardPath),
|
|
1724
|
+
),
|
|
1913
1725
|
];
|
|
1914
1726
|
recordCombinedEvent({
|
|
1915
1727
|
level: "error",
|
|
1916
|
-
agentId:
|
|
1917
|
-
message:
|
|
1728
|
+
agentId: failingGate.agentId || null,
|
|
1729
|
+
message: `${waveGateLabel(failingGateName)} blocked wave ${wave.wave}: ${failingGate.detail}`,
|
|
1918
1730
|
});
|
|
1919
1731
|
appendCoordination({
|
|
1920
1732
|
event: "wave_gate_blocked",
|
|
1921
1733
|
waves: [wave.wave],
|
|
1922
1734
|
status: "blocked",
|
|
1923
|
-
details: `agent=${
|
|
1924
|
-
actionRequested:
|
|
1735
|
+
details: `${failingGate.componentId ? `component=${failingGate.componentId}; ` : ""}${failingGate.agentId ? `agent=${failingGate.agentId}; ` : ""}reason=${failingGate.statusCode}; ${failingGate.detail}`,
|
|
1736
|
+
actionRequested: waveGateActionRequested(failingGateName, lanePaths),
|
|
1925
1737
|
});
|
|
1926
|
-
} else {
|
|
1738
|
+
} else if (authoritativeGateSnapshot?.contQaGate?.ok) {
|
|
1739
|
+
const contQaGate = authoritativeGateSnapshot.contQaGate;
|
|
1927
1740
|
setWaveDashboardAgent(dashboardState, contQaGate.agentId, {
|
|
1928
1741
|
detail: contQaGate.detail
|
|
1929
1742
|
? `Exit 0; cont-QA PASS (${contQaGate.detail})`
|
|
@@ -1938,127 +1751,21 @@ export async function runLauncherCli(argv) {
|
|
|
1938
1751
|
}
|
|
1939
1752
|
}
|
|
1940
1753
|
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
if (!infraGate.ok) {
|
|
1944
|
-
failures = [
|
|
1945
|
-
{
|
|
1946
|
-
agentId: infraGate.agentId,
|
|
1947
|
-
statusCode: infraGate.statusCode,
|
|
1948
|
-
logPath: infraGate.logPath || path.relative(REPO_ROOT, messageBoardPath),
|
|
1949
|
-
},
|
|
1950
|
-
];
|
|
1951
|
-
recordCombinedEvent({
|
|
1952
|
-
level: "error",
|
|
1953
|
-
agentId: infraGate.agentId,
|
|
1954
|
-
message: `Infra gate blocked wave ${wave.wave}: ${infraGate.detail}`,
|
|
1955
|
-
});
|
|
1956
|
-
appendCoordination({
|
|
1957
|
-
event: "wave_gate_blocked",
|
|
1958
|
-
waves: [wave.wave],
|
|
1959
|
-
status: "blocked",
|
|
1960
|
-
details: `agent=${infraGate.agentId}; reason=${infraGate.statusCode}; ${infraGate.detail}`,
|
|
1961
|
-
actionRequested: `Lane ${lanePaths.lane} owners should resolve the infra gate before wave progression.`,
|
|
1962
|
-
});
|
|
1963
|
-
}
|
|
1964
|
-
}
|
|
1965
|
-
|
|
1966
|
-
if (failures.length === 0) {
|
|
1967
|
-
const clarificationBarrier = readClarificationBarrier(derivedState);
|
|
1968
|
-
if (!clarificationBarrier.ok) {
|
|
1969
|
-
failures = [
|
|
1970
|
-
{
|
|
1971
|
-
agentId: lanePaths.integrationAgentId,
|
|
1972
|
-
statusCode: clarificationBarrier.statusCode,
|
|
1973
|
-
logPath: path.relative(REPO_ROOT, messageBoardPath),
|
|
1974
|
-
detail: clarificationBarrier.detail,
|
|
1975
|
-
},
|
|
1976
|
-
];
|
|
1977
|
-
recordCombinedEvent({
|
|
1978
|
-
level: "error",
|
|
1979
|
-
agentId: lanePaths.integrationAgentId,
|
|
1980
|
-
message: `Clarification barrier blocked wave ${wave.wave}: ${clarificationBarrier.detail}`,
|
|
1981
|
-
});
|
|
1982
|
-
appendCoordination({
|
|
1983
|
-
event: "wave_gate_blocked",
|
|
1984
|
-
waves: [wave.wave],
|
|
1985
|
-
status: "blocked",
|
|
1986
|
-
details: `reason=${clarificationBarrier.statusCode}; ${clarificationBarrier.detail}`,
|
|
1987
|
-
actionRequested: `Lane ${lanePaths.lane} owners should resolve open clarification chains before wave progression.`,
|
|
1988
|
-
});
|
|
1989
|
-
}
|
|
1990
|
-
}
|
|
1991
|
-
|
|
1992
|
-
const structuredSignals = Object.fromEntries(
|
|
1993
|
-
agentRuns.map((run) => [run.agent.agentId, parseStructuredSignalsFromLog(run.logPath)]),
|
|
1994
|
-
);
|
|
1995
|
-
const summariesByAgentId = Object.fromEntries(
|
|
1996
|
-
agentRuns
|
|
1997
|
-
.map((run) => [run.agent.agentId, readRunExecutionSummary(run, wave)])
|
|
1998
|
-
.filter(([, summary]) => summary),
|
|
1999
|
-
);
|
|
2000
|
-
const gateSnapshot = buildGateSnapshot({
|
|
2001
|
-
wave,
|
|
2002
|
-
agentRuns,
|
|
2003
|
-
derivedState,
|
|
2004
|
-
lanePaths,
|
|
2005
|
-
validationMode: "live",
|
|
2006
|
-
});
|
|
1754
|
+
const gateSnapshot =
|
|
1755
|
+
completionGateSnapshot || refreshReducerSnapshot(attempt).reducerState.gateSnapshot;
|
|
2007
1756
|
completionGateSnapshot = gateSnapshot;
|
|
2008
|
-
|
|
2009
|
-
computeReducerSnapshot({
|
|
2010
|
-
lanePaths,
|
|
2011
|
-
wave,
|
|
2012
|
-
agentRuns,
|
|
2013
|
-
derivedState,
|
|
2014
|
-
attempt,
|
|
2015
|
-
options,
|
|
2016
|
-
});
|
|
2017
|
-
} catch (error) {
|
|
2018
|
-
recordCombinedEvent({
|
|
2019
|
-
level: "warn",
|
|
2020
|
-
agentId: lanePaths.integrationAgentId,
|
|
2021
|
-
message: `Reducer shadow snapshot failed for wave ${wave.wave}: ${error instanceof Error ? error.message : String(error)}`,
|
|
2022
|
-
});
|
|
2023
|
-
}
|
|
2024
|
-
const traceDir = writeTraceBundle({
|
|
1757
|
+
const traceProjection = writeWaveAttemptTraceProjection({
|
|
2025
1758
|
tracesDir: lanePaths.tracesDir,
|
|
2026
1759
|
lanePaths,
|
|
2027
1760
|
launcherOptions: options,
|
|
2028
1761
|
wave,
|
|
2029
1762
|
attempt: traceAttempt,
|
|
2030
1763
|
manifest: buildManifest(lanePaths, [wave]),
|
|
2031
|
-
coordinationLogPath: derivedState.coordinationLogPath,
|
|
2032
|
-
coordinationState: derivedState.coordinationState,
|
|
2033
|
-
ledger: derivedState.ledger,
|
|
2034
|
-
docsQueue: derivedState.docsQueue,
|
|
2035
|
-
capabilityAssignments: derivedState.capabilityAssignments,
|
|
2036
|
-
dependencySnapshot: derivedState.dependencySnapshot,
|
|
2037
|
-
securitySummary: derivedState.securitySummary,
|
|
2038
|
-
integrationSummary: derivedState.integrationSummary,
|
|
2039
|
-
integrationMarkdownPath: derivedState.integrationMarkdownPath,
|
|
2040
|
-
proofRegistryPath: waveProofRegistryPath(lanePaths, wave.wave),
|
|
2041
|
-
controlPlanePath: path.join(lanePaths.controlPlaneDir, `wave-${wave.wave}.jsonl`),
|
|
2042
|
-
clarificationTriage: derivedState.clarificationTriage,
|
|
2043
1764
|
agentRuns,
|
|
2044
|
-
structuredSignals,
|
|
2045
1765
|
gateSnapshot,
|
|
2046
|
-
|
|
2047
|
-
tracesDir: lanePaths.tracesDir,
|
|
2048
|
-
wave,
|
|
2049
|
-
coordinationState: derivedState.coordinationState,
|
|
2050
|
-
integrationSummary: derivedState.integrationSummary,
|
|
2051
|
-
ledger: derivedState.ledger,
|
|
2052
|
-
docsQueue: derivedState.docsQueue,
|
|
2053
|
-
capabilityAssignments: derivedState.capabilityAssignments,
|
|
2054
|
-
dependencySnapshot: derivedState.dependencySnapshot,
|
|
2055
|
-
summariesByAgentId,
|
|
2056
|
-
agentRuns,
|
|
2057
|
-
gateSnapshot,
|
|
2058
|
-
attempt: traceAttempt,
|
|
2059
|
-
coordinationLogPath: derivedState.coordinationLogPath,
|
|
2060
|
-
}),
|
|
1766
|
+
derivedState,
|
|
2061
1767
|
});
|
|
1768
|
+
const traceDir = traceProjection.traceDir;
|
|
2062
1769
|
completionTraceDir = traceDir;
|
|
2063
1770
|
appendWaveControlEvent(lanePaths, wave.wave, {
|
|
2064
1771
|
entityType: "gate",
|
|
@@ -2092,7 +1799,7 @@ export async function runLauncherCli(argv) {
|
|
|
2092
1799
|
wave,
|
|
2093
1800
|
);
|
|
2094
1801
|
if (sharedComponentContinuationRuns.length > 0) {
|
|
2095
|
-
recordAttemptState(attempt, "completed", {
|
|
1802
|
+
recordAttemptState(lanePaths, wave.wave, attempt, "completed", {
|
|
2096
1803
|
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2097
1804
|
detail: `Attempt completed; continuing with sibling owners ${sharedComponentContinuationRuns.map((run) => run.agent.agentId).join(", ")}.`,
|
|
2098
1805
|
});
|
|
@@ -2115,22 +1822,13 @@ export async function runLauncherCli(argv) {
|
|
|
2115
1822
|
detail: "Queued for shared component closure",
|
|
2116
1823
|
});
|
|
2117
1824
|
}
|
|
2118
|
-
|
|
2119
|
-
|
|
1825
|
+
writeWaveRelaunchProjection({
|
|
1826
|
+
lanePaths,
|
|
1827
|
+
wave,
|
|
2120
1828
|
attempt,
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
executorStates: Object.fromEntries(
|
|
2125
|
-
runsToLaunch.map((run) => [run.agent.agentId, run.agent.executorResolved || null]),
|
|
2126
|
-
),
|
|
2127
|
-
fallbackHistory: Object.fromEntries(
|
|
2128
|
-
runsToLaunch.map((run) => [
|
|
2129
|
-
run.agent.agentId,
|
|
2130
|
-
run.agent.executorResolved?.executorHistory || [],
|
|
2131
|
-
]),
|
|
2132
|
-
),
|
|
2133
|
-
createdAt: toIsoTimestamp(),
|
|
1829
|
+
runs: runsToLaunch,
|
|
1830
|
+
failures,
|
|
1831
|
+
derivedState,
|
|
2134
1832
|
});
|
|
2135
1833
|
flushDashboards();
|
|
2136
1834
|
traceAttempt += 1;
|
|
@@ -2138,23 +1836,14 @@ export async function runLauncherCli(argv) {
|
|
|
2138
1836
|
}
|
|
2139
1837
|
|
|
2140
1838
|
if (failures.length === 0) {
|
|
2141
|
-
recordAttemptState(attempt, "completed", {
|
|
1839
|
+
recordAttemptState(lanePaths, wave.wave, attempt, "completed", {
|
|
2142
1840
|
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2143
1841
|
detail: "Wave gates passed for this attempt.",
|
|
2144
1842
|
});
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
source: "launcher",
|
|
2150
|
-
actor: "launcher",
|
|
2151
|
-
data: {
|
|
2152
|
-
waveId: `wave-${wave.wave}`,
|
|
2153
|
-
waveNumber: wave.wave,
|
|
2154
|
-
attempts: attempt,
|
|
2155
|
-
traceDir: completionTraceDir ? path.relative(REPO_ROOT, completionTraceDir) : null,
|
|
2156
|
-
gateSnapshot: completionGateSnapshot,
|
|
2157
|
-
},
|
|
1843
|
+
recordWaveRunState(lanePaths, wave.wave, "completed", {
|
|
1844
|
+
attempts: attempt,
|
|
1845
|
+
traceDir: completionTraceDir ? path.relative(REPO_ROOT, completionTraceDir) : null,
|
|
1846
|
+
gateSnapshot: completionGateSnapshot,
|
|
2158
1847
|
});
|
|
2159
1848
|
dashboardState.status = "completed";
|
|
2160
1849
|
recordCombinedEvent({ message: `Wave ${wave.wave} completed successfully.` });
|
|
@@ -2168,30 +1857,21 @@ export async function runLauncherCli(argv) {
|
|
|
2168
1857
|
}
|
|
2169
1858
|
|
|
2170
1859
|
if (attempt >= options.maxRetriesPerWave + 1) {
|
|
2171
|
-
recordAttemptState(attempt, "failed", {
|
|
1860
|
+
recordAttemptState(lanePaths, wave.wave, attempt, "failed", {
|
|
2172
1861
|
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2173
1862
|
detail: failures
|
|
2174
1863
|
.map((failure) => `${failure.agentId || "wave"}:${failure.statusCode}`)
|
|
2175
1864
|
.join(", "),
|
|
2176
1865
|
});
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
attempts: attempt,
|
|
2187
|
-
traceDir: completionTraceDir ? path.relative(REPO_ROOT, completionTraceDir) : null,
|
|
2188
|
-
gateSnapshot: completionGateSnapshot,
|
|
2189
|
-
failures: failures.map((failure) => ({
|
|
2190
|
-
agentId: failure.agentId || null,
|
|
2191
|
-
statusCode: failure.statusCode,
|
|
2192
|
-
detail: failure.detail || null,
|
|
2193
|
-
})),
|
|
2194
|
-
},
|
|
1866
|
+
recordWaveRunState(lanePaths, wave.wave, "failed", {
|
|
1867
|
+
attempts: attempt,
|
|
1868
|
+
traceDir: completionTraceDir ? path.relative(REPO_ROOT, completionTraceDir) : null,
|
|
1869
|
+
gateSnapshot: completionGateSnapshot,
|
|
1870
|
+
failures: failures.map((failure) => ({
|
|
1871
|
+
agentId: failure.agentId || null,
|
|
1872
|
+
statusCode: failure.statusCode,
|
|
1873
|
+
detail: failure.detail || null,
|
|
1874
|
+
})),
|
|
2195
1875
|
});
|
|
2196
1876
|
dashboardState.status = timedOut ? "timed_out" : "failed";
|
|
2197
1877
|
for (const failure of failures) {
|
|
@@ -2225,7 +1905,7 @@ export async function runLauncherCli(argv) {
|
|
|
2225
1905
|
|
|
2226
1906
|
const failedAgentIds = new Set(failures.map((failure) => failure.agentId));
|
|
2227
1907
|
const failedList = Array.from(failedAgentIds).join(", ");
|
|
2228
|
-
recordAttemptState(attempt, "failed", {
|
|
1908
|
+
recordAttemptState(lanePaths, wave.wave, attempt, "failed", {
|
|
2229
1909
|
selectedAgentIds: runsToLaunch.map((run) => run.agent.agentId),
|
|
2230
1910
|
detail: failures
|
|
2231
1911
|
.map((failure) => `${failure.agentId || "wave"}:${failure.statusCode}`)
|
|
@@ -2241,20 +1921,19 @@ export async function runLauncherCli(argv) {
|
|
|
2241
1921
|
details: `attempt=${attempt + 1}/${options.maxRetriesPerWave + 1}; failed_agents=${failedList}; timed_out=${timedOut ? "yes" : "no"}`,
|
|
2242
1922
|
actionRequested: `Lane ${lanePaths.lane} owners should inspect failed agent logs before retry completion.`,
|
|
2243
1923
|
});
|
|
2244
|
-
|
|
1924
|
+
retryOverride = readWaveRetryOverride(lanePaths, wave.wave);
|
|
1925
|
+
const reducerDecision = refreshReducerSnapshot(attempt);
|
|
1926
|
+
const retryPlan = planRetryWaveAttempt({
|
|
2245
1927
|
agentRuns,
|
|
2246
1928
|
failures,
|
|
2247
1929
|
derivedState,
|
|
2248
1930
|
lanePaths,
|
|
2249
1931
|
wave,
|
|
2250
|
-
);
|
|
2251
|
-
retryOverride = readWaveRetryOverride(lanePaths, wave.wave);
|
|
2252
|
-
const overrideResolution = resolveRetryOverrideRuns(
|
|
2253
|
-
agentRuns,
|
|
2254
1932
|
retryOverride,
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
1933
|
+
waveState: reducerDecision?.reducerState || null,
|
|
1934
|
+
});
|
|
1935
|
+
const relaunchResolution = retryPlan.relaunchResolution;
|
|
1936
|
+
const overrideResolution = retryPlan.overrideResolution;
|
|
2258
1937
|
if (overrideResolution.unknownAgentIds.length > 0) {
|
|
2259
1938
|
appendCoordination({
|
|
2260
1939
|
event: "retry_override_invalid",
|
|
@@ -2266,8 +1945,8 @@ export async function runLauncherCli(argv) {
|
|
|
2266
1945
|
});
|
|
2267
1946
|
clearWaveRetryOverride(lanePaths, wave.wave);
|
|
2268
1947
|
retryOverride = null;
|
|
2269
|
-
} else if (overrideResolution.runs.length > 0) {
|
|
2270
|
-
runsToLaunch =
|
|
1948
|
+
} else if (retryPlan.source === "override" && overrideResolution.runs.length > 0) {
|
|
1949
|
+
runsToLaunch = retryPlan.selectedRuns;
|
|
2271
1950
|
appendCoordination({
|
|
2272
1951
|
event: "retry_override_applied",
|
|
2273
1952
|
waves: [wave.wave],
|
|
@@ -2306,7 +1985,7 @@ export async function runLauncherCli(argv) {
|
|
|
2306
1985
|
error.exitCode = 43;
|
|
2307
1986
|
throw error;
|
|
2308
1987
|
} else {
|
|
2309
|
-
runsToLaunch =
|
|
1988
|
+
runsToLaunch = retryPlan.selectedRuns;
|
|
2310
1989
|
}
|
|
2311
1990
|
if (runsToLaunch.length === 0) {
|
|
2312
1991
|
clearWaveRelaunchPlan(lanePaths, wave.wave);
|
|
@@ -2322,22 +2001,13 @@ export async function runLauncherCli(argv) {
|
|
|
2322
2001
|
detail: "Queued for retry",
|
|
2323
2002
|
});
|
|
2324
2003
|
}
|
|
2325
|
-
|
|
2326
|
-
|
|
2004
|
+
writeWaveRelaunchProjection({
|
|
2005
|
+
lanePaths,
|
|
2006
|
+
wave,
|
|
2327
2007
|
attempt: attempt + 1,
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
executorStates: Object.fromEntries(
|
|
2332
|
-
runsToLaunch.map((run) => [run.agent.agentId, run.agent.executorResolved || null]),
|
|
2333
|
-
),
|
|
2334
|
-
fallbackHistory: Object.fromEntries(
|
|
2335
|
-
runsToLaunch.map((run) => [
|
|
2336
|
-
run.agent.agentId,
|
|
2337
|
-
run.agent.executorResolved?.executorHistory || [],
|
|
2338
|
-
]),
|
|
2339
|
-
),
|
|
2340
|
-
createdAt: toIsoTimestamp(),
|
|
2008
|
+
runs: runsToLaunch,
|
|
2009
|
+
failures,
|
|
2010
|
+
derivedState,
|
|
2341
2011
|
});
|
|
2342
2012
|
flushDashboards();
|
|
2343
2013
|
attempt += 1;
|
|
@@ -2390,14 +2060,14 @@ export async function runLauncherCli(argv) {
|
|
|
2390
2060
|
if (WAVE_TERMINAL_STATES.has(globalWave.status)) {
|
|
2391
2061
|
globalWave.completedAt = toIsoTimestamp();
|
|
2392
2062
|
}
|
|
2393
|
-
|
|
2063
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
2394
2064
|
}
|
|
2395
2065
|
}
|
|
2396
2066
|
}
|
|
2397
2067
|
|
|
2398
2068
|
globalDashboard.status = "completed";
|
|
2399
2069
|
recordGlobalDashboardEvent(globalDashboard, { message: "All selected waves completed." });
|
|
2400
|
-
|
|
2070
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
2401
2071
|
appendCoordination({
|
|
2402
2072
|
event: "launcher_finish",
|
|
2403
2073
|
waves: selectedWavesForCoordination,
|
|
@@ -2412,6 +2082,7 @@ export async function runLauncherCli(argv) {
|
|
|
2412
2082
|
appendCoordination,
|
|
2413
2083
|
error,
|
|
2414
2084
|
);
|
|
2085
|
+
writeDashboardProjections({ lanePaths, globalDashboard });
|
|
2415
2086
|
throw error;
|
|
2416
2087
|
} finally {
|
|
2417
2088
|
if (globalDashboardTerminalAppended && globalDashboardTerminalEntry && !options.keepTerminals) {
|
|
@@ -2446,127 +2117,3 @@ export async function runLauncherCli(argv) {
|
|
|
2446
2117
|
}
|
|
2447
2118
|
}
|
|
2448
2119
|
}
|
|
2449
|
-
|
|
2450
|
-
/**
|
|
2451
|
-
* Compute and persist a reducer snapshot alongside the traditional gate evaluation.
|
|
2452
|
-
* Shadow mode: the reducer runs and its output is written to disk, but decisions
|
|
2453
|
-
* still come from the traditional gate readers. This enables comparison and validation.
|
|
2454
|
-
*
|
|
2455
|
-
* @param {object} params
|
|
2456
|
-
* @param {object} params.lanePaths
|
|
2457
|
-
* @param {object} params.wave - Wave definition
|
|
2458
|
-
* @param {object} params.agentRuns - Array of run info objects
|
|
2459
|
-
* @param {object} params.derivedState - Current derived state
|
|
2460
|
-
* @param {number} params.attempt - Current attempt number
|
|
2461
|
-
* @param {object} params.options - Launcher options
|
|
2462
|
-
* @returns {object} { reducerState, resumePlan, snapshotPath }
|
|
2463
|
-
*/
|
|
2464
|
-
export function computeReducerSnapshot({
|
|
2465
|
-
lanePaths,
|
|
2466
|
-
wave,
|
|
2467
|
-
agentRuns,
|
|
2468
|
-
derivedState,
|
|
2469
|
-
attempt,
|
|
2470
|
-
options = {},
|
|
2471
|
-
}) {
|
|
2472
|
-
// Build agentResults from agentRuns
|
|
2473
|
-
const agentResults = {};
|
|
2474
|
-
for (const run of agentRuns) {
|
|
2475
|
-
const summary = readRunExecutionSummary(run, wave);
|
|
2476
|
-
if (summary) {
|
|
2477
|
-
agentResults[run.agent.agentId] = summary;
|
|
2478
|
-
}
|
|
2479
|
-
}
|
|
2480
|
-
|
|
2481
|
-
// Load canonical event sources
|
|
2482
|
-
const controlPlaneLogPath = path.join(
|
|
2483
|
-
lanePaths.controlPlaneDir,
|
|
2484
|
-
`wave-${wave.wave}.jsonl`,
|
|
2485
|
-
);
|
|
2486
|
-
const controlPlaneEvents = fs.existsSync(controlPlaneLogPath)
|
|
2487
|
-
? readControlPlaneEvents(controlPlaneLogPath)
|
|
2488
|
-
: [];
|
|
2489
|
-
|
|
2490
|
-
const coordinationLogPath = path.join(
|
|
2491
|
-
lanePaths.coordinationDir,
|
|
2492
|
-
`wave-${wave.wave}.jsonl`,
|
|
2493
|
-
);
|
|
2494
|
-
const coordinationRecords = fs.existsSync(coordinationLogPath)
|
|
2495
|
-
? readMaterializedCoordinationState(coordinationLogPath)
|
|
2496
|
-
: null;
|
|
2497
|
-
|
|
2498
|
-
const feedbackRequests = readWaveHumanFeedbackRequests({
|
|
2499
|
-
feedbackRequestsDir: lanePaths.feedbackRequestsDir,
|
|
2500
|
-
lane: lanePaths.lane,
|
|
2501
|
-
waveNumber: wave.wave,
|
|
2502
|
-
agentIds: (agentRuns || []).map((run) => run.agent.agentId),
|
|
2503
|
-
orchestratorId: options.orchestratorId,
|
|
2504
|
-
});
|
|
2505
|
-
|
|
2506
|
-
// Build dependency tickets from derivedState
|
|
2507
|
-
const dependencyTickets = derivedState?.dependencySnapshot || null;
|
|
2508
|
-
|
|
2509
|
-
// Run the reducer
|
|
2510
|
-
const reducerState = reduceWaveState({
|
|
2511
|
-
controlPlaneEvents,
|
|
2512
|
-
coordinationRecords: coordinationRecords?.latestRecords || [],
|
|
2513
|
-
agentResults,
|
|
2514
|
-
waveDefinition: wave,
|
|
2515
|
-
dependencyTickets,
|
|
2516
|
-
feedbackRequests: feedbackRequests || [],
|
|
2517
|
-
laneConfig: {
|
|
2518
|
-
lane: lanePaths.lane,
|
|
2519
|
-
contQaAgentId: lanePaths.contQaAgentId || "A0",
|
|
2520
|
-
contEvalAgentId: lanePaths.contEvalAgentId || "E0",
|
|
2521
|
-
integrationAgentId: lanePaths.integrationAgentId || "A8",
|
|
2522
|
-
documentationAgentId: lanePaths.documentationAgentId || "A9",
|
|
2523
|
-
validationMode: "live",
|
|
2524
|
-
evalTargets: wave.evalTargets,
|
|
2525
|
-
benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
|
|
2526
|
-
laneProfile: lanePaths.laneProfile,
|
|
2527
|
-
requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
|
|
2528
|
-
capabilityRouting: lanePaths.capabilityRouting,
|
|
2529
|
-
},
|
|
2530
|
-
});
|
|
2531
|
-
|
|
2532
|
-
// Build resume plan
|
|
2533
|
-
const resumePlan = buildResumePlan(reducerState, {
|
|
2534
|
-
waveDefinition: wave,
|
|
2535
|
-
lanePaths,
|
|
2536
|
-
});
|
|
2537
|
-
|
|
2538
|
-
// Persist snapshot
|
|
2539
|
-
const stateDir = path.join(lanePaths.stateDir, "reducer");
|
|
2540
|
-
ensureDirectory(stateDir);
|
|
2541
|
-
const snapshotPath = path.join(stateDir, `wave-${wave.wave}.json`);
|
|
2542
|
-
writeWaveStateSnapshot(snapshotPath, {
|
|
2543
|
-
...reducerState,
|
|
2544
|
-
attempt,
|
|
2545
|
-
resumePlan,
|
|
2546
|
-
}, {
|
|
2547
|
-
lane: lanePaths.lane,
|
|
2548
|
-
wave: wave.wave,
|
|
2549
|
-
});
|
|
2550
|
-
|
|
2551
|
-
return {
|
|
2552
|
-
reducerState,
|
|
2553
|
-
resumePlan,
|
|
2554
|
-
snapshotPath,
|
|
2555
|
-
};
|
|
2556
|
-
}
|
|
2557
|
-
|
|
2558
|
-
/**
|
|
2559
|
-
* Read a previously persisted reducer snapshot from disk.
|
|
2560
|
-
*
|
|
2561
|
-
* @param {object} lanePaths
|
|
2562
|
-
* @param {number} waveNumber
|
|
2563
|
-
* @returns {object|null} The persisted snapshot, or null if not found
|
|
2564
|
-
*/
|
|
2565
|
-
export function readPersistedReducerSnapshot(lanePaths, waveNumber) {
|
|
2566
|
-
const stateDir = path.join(lanePaths.stateDir, "reducer");
|
|
2567
|
-
const snapshotPath = path.join(stateDir, `wave-${waveNumber}.json`);
|
|
2568
|
-
return readWaveStateSnapshot(snapshotPath, {
|
|
2569
|
-
lane: lanePaths.lane,
|
|
2570
|
-
wave: waveNumber,
|
|
2571
|
-
});
|
|
2572
|
-
}
|