@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
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import {
|
|
3
|
+
writeAssignmentSnapshot,
|
|
4
|
+
writeDependencySnapshot,
|
|
5
|
+
} from "./artifact-schemas.mjs";
|
|
6
|
+
import {
|
|
7
|
+
syncGlobalWaveFromWaveDashboard,
|
|
8
|
+
writeGlobalDashboard,
|
|
9
|
+
writeWaveDashboard,
|
|
10
|
+
} from "./dashboard-state.mjs";
|
|
11
|
+
import { writeDocsQueue } from "./docs-queue.mjs";
|
|
12
|
+
import { writeWaveLedger } from "./ledger.mjs";
|
|
13
|
+
import { writeDependencySnapshotMarkdown } from "./routing-state.mjs";
|
|
14
|
+
import {
|
|
15
|
+
writeCompiledInbox,
|
|
16
|
+
writeCoordinationBoardProjection,
|
|
17
|
+
writeJsonArtifact,
|
|
18
|
+
} from "./coordination-store.mjs";
|
|
19
|
+
import { parseStructuredSignalsFromLog } from "./dashboard-state.mjs";
|
|
20
|
+
import { readRunExecutionSummary } from "./gate-engine.mjs";
|
|
21
|
+
import { waveProofRegistryPath } from "./proof-registry.mjs";
|
|
22
|
+
import { relaunchReasonBuckets, writeWaveRelaunchPlan } from "./retry-engine.mjs";
|
|
23
|
+
import { toIsoTimestamp, writeTextAtomic } from "./shared.mjs";
|
|
24
|
+
import { buildQualityMetrics, writeTraceBundle } from "./traces.mjs";
|
|
25
|
+
|
|
26
|
+
export function writeWaveDerivedProjections({ lanePaths, wave, derivedState }) {
|
|
27
|
+
if (!derivedState) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
writeAssignmentSnapshot(derivedState.assignmentSnapshotPath, derivedState.capabilityAssignments, {
|
|
31
|
+
lane: lanePaths.lane,
|
|
32
|
+
wave: wave.wave,
|
|
33
|
+
});
|
|
34
|
+
writeDependencySnapshot(
|
|
35
|
+
derivedState.dependencySnapshotPath,
|
|
36
|
+
derivedState.dependencySnapshot,
|
|
37
|
+
{
|
|
38
|
+
lane: lanePaths.lane,
|
|
39
|
+
wave: wave.wave,
|
|
40
|
+
},
|
|
41
|
+
);
|
|
42
|
+
writeDependencySnapshotMarkdown(
|
|
43
|
+
derivedState.dependencySnapshotMarkdownPath,
|
|
44
|
+
derivedState.dependencySnapshot,
|
|
45
|
+
);
|
|
46
|
+
writeDocsQueue(derivedState.docsQueuePath, derivedState.docsQueue);
|
|
47
|
+
writeJsonArtifact(derivedState.securitySummaryPath, derivedState.securitySummary);
|
|
48
|
+
writeTextAtomic(
|
|
49
|
+
derivedState.securityMarkdownPath,
|
|
50
|
+
`${derivedState.securitySummary ? renderWaveSecuritySummaryMarkdown(derivedState.securitySummary) : ""}\n`,
|
|
51
|
+
);
|
|
52
|
+
writeJsonArtifact(derivedState.integrationSummaryPath, derivedState.integrationSummary);
|
|
53
|
+
writeTextAtomic(
|
|
54
|
+
derivedState.integrationMarkdownPath,
|
|
55
|
+
`${derivedState.integrationSummary ? renderIntegrationSummaryMarkdown(derivedState.integrationSummary) : ""}\n`,
|
|
56
|
+
);
|
|
57
|
+
writeWaveLedger(derivedState.ledgerPath, derivedState.ledger);
|
|
58
|
+
writeCompiledInbox(derivedState.sharedSummaryPath, derivedState.sharedSummaryText);
|
|
59
|
+
for (const inbox of Object.values(derivedState.inboxesByAgentId || {})) {
|
|
60
|
+
writeCompiledInbox(inbox.path, inbox.text);
|
|
61
|
+
}
|
|
62
|
+
writeCoordinationBoardProjection(derivedState.messageBoardPath, {
|
|
63
|
+
wave: wave.wave,
|
|
64
|
+
waveFile: wave.file,
|
|
65
|
+
agents: wave.agents,
|
|
66
|
+
state: derivedState.coordinationState,
|
|
67
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
68
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
69
|
+
});
|
|
70
|
+
return derivedState;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function writeDashboardProjections({
|
|
74
|
+
lanePaths,
|
|
75
|
+
globalDashboard = null,
|
|
76
|
+
dashboardState = null,
|
|
77
|
+
dashboardPath = null,
|
|
78
|
+
}) {
|
|
79
|
+
if (dashboardState && dashboardPath) {
|
|
80
|
+
writeWaveDashboard(dashboardPath, dashboardState);
|
|
81
|
+
}
|
|
82
|
+
if (globalDashboard && dashboardState) {
|
|
83
|
+
syncGlobalWaveFromWaveDashboard(globalDashboard, dashboardState);
|
|
84
|
+
}
|
|
85
|
+
if (globalDashboard) {
|
|
86
|
+
writeGlobalDashboard(lanePaths.globalDashboardPath, globalDashboard);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function writeWaveAttemptTraceProjection({
|
|
91
|
+
lanePaths,
|
|
92
|
+
wave,
|
|
93
|
+
attempt,
|
|
94
|
+
launcherOptions,
|
|
95
|
+
derivedState,
|
|
96
|
+
manifest,
|
|
97
|
+
agentRuns,
|
|
98
|
+
gateSnapshot,
|
|
99
|
+
tracesDir,
|
|
100
|
+
}) {
|
|
101
|
+
const structuredSignals = Object.fromEntries(
|
|
102
|
+
agentRuns.map((run) => [run.agent.agentId, parseStructuredSignalsFromLog(run.logPath)]),
|
|
103
|
+
);
|
|
104
|
+
const summariesByAgentId = Object.fromEntries(
|
|
105
|
+
agentRuns
|
|
106
|
+
.map((run) => [run.agent.agentId, readRunExecutionSummary(run, wave, { mode: "compat" })])
|
|
107
|
+
.filter(([, summary]) => summary),
|
|
108
|
+
);
|
|
109
|
+
const traceDir = writeTraceBundle({
|
|
110
|
+
tracesDir,
|
|
111
|
+
lanePaths,
|
|
112
|
+
launcherOptions,
|
|
113
|
+
wave,
|
|
114
|
+
attempt,
|
|
115
|
+
manifest,
|
|
116
|
+
coordinationLogPath: derivedState.coordinationLogPath,
|
|
117
|
+
coordinationState: derivedState.coordinationState,
|
|
118
|
+
ledger: derivedState.ledger,
|
|
119
|
+
docsQueue: derivedState.docsQueue,
|
|
120
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
121
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
122
|
+
securitySummary: derivedState.securitySummary,
|
|
123
|
+
integrationSummary: derivedState.integrationSummary,
|
|
124
|
+
integrationMarkdownPath: derivedState.integrationMarkdownPath,
|
|
125
|
+
proofRegistryPath: lanePaths.proofDir ? waveProofRegistryPath(lanePaths, wave.wave) : null,
|
|
126
|
+
controlPlanePath: path.join(lanePaths.controlPlaneDir, `wave-${wave.wave}.jsonl`),
|
|
127
|
+
clarificationTriage: derivedState.clarificationTriage,
|
|
128
|
+
agentRuns,
|
|
129
|
+
structuredSignals,
|
|
130
|
+
gateSnapshot,
|
|
131
|
+
quality: buildQualityMetrics({
|
|
132
|
+
tracesDir,
|
|
133
|
+
wave,
|
|
134
|
+
coordinationState: derivedState.coordinationState,
|
|
135
|
+
integrationSummary: derivedState.integrationSummary,
|
|
136
|
+
ledger: derivedState.ledger,
|
|
137
|
+
docsQueue: derivedState.docsQueue,
|
|
138
|
+
capabilityAssignments: derivedState.capabilityAssignments,
|
|
139
|
+
dependencySnapshot: derivedState.dependencySnapshot,
|
|
140
|
+
summariesByAgentId,
|
|
141
|
+
agentRuns,
|
|
142
|
+
gateSnapshot,
|
|
143
|
+
attempt,
|
|
144
|
+
coordinationLogPath: derivedState.coordinationLogPath,
|
|
145
|
+
}),
|
|
146
|
+
});
|
|
147
|
+
return {
|
|
148
|
+
traceDir,
|
|
149
|
+
structuredSignals,
|
|
150
|
+
summariesByAgentId,
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export function writeWaveRelaunchProjection({
|
|
155
|
+
lanePaths,
|
|
156
|
+
wave,
|
|
157
|
+
attempt,
|
|
158
|
+
runs,
|
|
159
|
+
failures,
|
|
160
|
+
derivedState,
|
|
161
|
+
}) {
|
|
162
|
+
writeWaveRelaunchPlan(lanePaths, wave.wave, {
|
|
163
|
+
wave: wave.wave,
|
|
164
|
+
attempt,
|
|
165
|
+
phase: derivedState?.ledger?.phase || null,
|
|
166
|
+
selectedAgentIds: runs.map((run) => run.agent.agentId),
|
|
167
|
+
reasonBuckets: relaunchReasonBuckets(runs, failures, derivedState),
|
|
168
|
+
executorStates: Object.fromEntries(
|
|
169
|
+
runs.map((run) => [run.agent.agentId, run.agent.executorResolved || null]),
|
|
170
|
+
),
|
|
171
|
+
fallbackHistory: Object.fromEntries(
|
|
172
|
+
runs.map((run) => [
|
|
173
|
+
run.agent.agentId,
|
|
174
|
+
run.agent.executorResolved?.executorHistory || [],
|
|
175
|
+
]),
|
|
176
|
+
),
|
|
177
|
+
createdAt: toIsoTimestamp(),
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function renderWaveSecuritySummaryMarkdown(securitySummary) {
|
|
182
|
+
return [
|
|
183
|
+
`# Wave ${securitySummary.wave} Security Summary`,
|
|
184
|
+
"",
|
|
185
|
+
`- State: ${securitySummary.overallState || "unknown"}`,
|
|
186
|
+
`- Detail: ${securitySummary.detail || "n/a"}`,
|
|
187
|
+
`- Total findings: ${securitySummary.totalFindings || 0}`,
|
|
188
|
+
`- Total approvals: ${securitySummary.totalApprovals || 0}`,
|
|
189
|
+
`- Reviewers: ${(securitySummary.agents || []).length}`,
|
|
190
|
+
"",
|
|
191
|
+
"## Reviews",
|
|
192
|
+
...((securitySummary.agents || []).length > 0
|
|
193
|
+
? securitySummary.agents.map(
|
|
194
|
+
(entry) =>
|
|
195
|
+
`- ${entry.agentId}: state=${entry.state || "unknown"} findings=${entry.findings || 0} approvals=${entry.approvals || 0}${entry.reportPath ? ` report=${entry.reportPath}` : ""}${entry.detail ? ` detail=${entry.detail}` : ""}`,
|
|
196
|
+
)
|
|
197
|
+
: ["- None."]),
|
|
198
|
+
"",
|
|
199
|
+
].join("\n");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function renderIntegrationSection(title, items) {
|
|
203
|
+
return [
|
|
204
|
+
title,
|
|
205
|
+
...((items || []).length > 0 ? items.map((item) => `- ${item}`) : ["- None."]),
|
|
206
|
+
"",
|
|
207
|
+
];
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
211
|
+
return [
|
|
212
|
+
`# Wave ${integrationSummary.wave} Integration Summary`,
|
|
213
|
+
"",
|
|
214
|
+
`- Recommendation: ${integrationSummary.recommendation || "unknown"}`,
|
|
215
|
+
`- Detail: ${integrationSummary.detail || "n/a"}`,
|
|
216
|
+
`- Open claims: ${(integrationSummary.openClaims || []).length}`,
|
|
217
|
+
`- Conflicting claims: ${(integrationSummary.conflictingClaims || []).length}`,
|
|
218
|
+
`- Unresolved blockers: ${(integrationSummary.unresolvedBlockers || []).length}`,
|
|
219
|
+
`- Changed interfaces: ${(integrationSummary.changedInterfaces || []).length}`,
|
|
220
|
+
`- Cross-component impacts: ${(integrationSummary.crossComponentImpacts || []).length}`,
|
|
221
|
+
`- Proof gaps: ${(integrationSummary.proofGaps || []).length}`,
|
|
222
|
+
`- Deploy risks: ${(integrationSummary.deployRisks || []).length}`,
|
|
223
|
+
`- Documentation gaps: ${(integrationSummary.docGaps || []).length}`,
|
|
224
|
+
`- Security review: ${integrationSummary.securityState || "not-applicable"}`,
|
|
225
|
+
`- Security findings: ${(integrationSummary.securityFindings || []).length}`,
|
|
226
|
+
`- Security approvals: ${(integrationSummary.securityApprovals || []).length}`,
|
|
227
|
+
`- Inbound dependencies: ${(integrationSummary.inboundDependencies || []).length}`,
|
|
228
|
+
`- Outbound dependencies: ${(integrationSummary.outboundDependencies || []).length}`,
|
|
229
|
+
`- Helper assignments: ${(integrationSummary.helperAssignments || []).length}`,
|
|
230
|
+
"",
|
|
231
|
+
...renderIntegrationSection("## Open Claims", integrationSummary.openClaims),
|
|
232
|
+
...renderIntegrationSection("## Conflicting Claims", integrationSummary.conflictingClaims),
|
|
233
|
+
...renderIntegrationSection("## Unresolved Blockers", integrationSummary.unresolvedBlockers),
|
|
234
|
+
...renderIntegrationSection("## Changed Interfaces", integrationSummary.changedInterfaces),
|
|
235
|
+
...renderIntegrationSection(
|
|
236
|
+
"## Cross-Component Impacts",
|
|
237
|
+
integrationSummary.crossComponentImpacts,
|
|
238
|
+
),
|
|
239
|
+
...renderIntegrationSection("## Proof Gaps", integrationSummary.proofGaps),
|
|
240
|
+
...renderIntegrationSection("## Deploy Risks", integrationSummary.deployRisks),
|
|
241
|
+
...renderIntegrationSection("## Security Findings", integrationSummary.securityFindings),
|
|
242
|
+
...renderIntegrationSection("## Security Approvals", integrationSummary.securityApprovals),
|
|
243
|
+
...renderIntegrationSection("## Inbound Dependencies", integrationSummary.inboundDependencies),
|
|
244
|
+
...renderIntegrationSection("## Outbound Dependencies", integrationSummary.outboundDependencies),
|
|
245
|
+
...renderIntegrationSection("## Helper Assignments", integrationSummary.helperAssignments),
|
|
246
|
+
"## Runtime Assignments",
|
|
247
|
+
...((integrationSummary.runtimeAssignments || []).length > 0
|
|
248
|
+
? integrationSummary.runtimeAssignments.map(
|
|
249
|
+
(assignment) =>
|
|
250
|
+
`- ${assignment.agentId}: executor=${assignment.executorId || "n/a"} role=${assignment.role || "n/a"} profile=${assignment.profile || "none"} fallback_used=${assignment.fallbackUsed ? "yes" : "no"}`,
|
|
251
|
+
)
|
|
252
|
+
: ["- None."]),
|
|
253
|
+
"",
|
|
254
|
+
...renderIntegrationSection("## Documentation Gaps", integrationSummary.docGaps),
|
|
255
|
+
].join("\n");
|
|
256
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { compactSingleLine } from "./shared.mjs";
|
|
2
|
+
|
|
3
|
+
export function formatReconcileBlockedWaveLine(blockedWave) {
|
|
4
|
+
const parts = Array.isArray(blockedWave?.reasons)
|
|
5
|
+
? blockedWave.reasons
|
|
6
|
+
.map((reason) => {
|
|
7
|
+
const code = compactSingleLine(reason?.code || "", 80);
|
|
8
|
+
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
9
|
+
return code && detail ? `${code}=${detail}` : "";
|
|
10
|
+
})
|
|
11
|
+
.filter(Boolean)
|
|
12
|
+
: [];
|
|
13
|
+
return `[reconcile] wave ${blockedWave?.wave ?? "unknown"} not reconstructable: ${
|
|
14
|
+
parts.join("; ") || "unknown reason"
|
|
15
|
+
}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function formatReconcilePreservedWaveLine(preservedWave) {
|
|
19
|
+
const parts = Array.isArray(preservedWave?.reasons)
|
|
20
|
+
? preservedWave.reasons
|
|
21
|
+
.map((reason) => {
|
|
22
|
+
const code = compactSingleLine(reason?.code || "", 80);
|
|
23
|
+
const detail = compactSingleLine(reason?.detail || "", 240);
|
|
24
|
+
return code && detail ? `${code}=${detail}` : "";
|
|
25
|
+
})
|
|
26
|
+
.filter(Boolean)
|
|
27
|
+
: [];
|
|
28
|
+
const previousState = compactSingleLine(preservedWave?.previousState || "completed", 80);
|
|
29
|
+
return `[reconcile] wave ${preservedWave?.wave ?? "unknown"} preserved as ${previousState}: ${
|
|
30
|
+
parts.join("; ") || "unknown reason"
|
|
31
|
+
}`;
|
|
32
|
+
}
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
isOpenCoordinationStatus,
|
|
5
|
+
openClarificationLinkedRequests,
|
|
6
|
+
readMaterializedCoordinationState,
|
|
7
|
+
} from "./coordination-store.mjs";
|
|
8
|
+
import { readWaveHumanFeedbackRequests } from "./coordination.mjs";
|
|
9
|
+
import { readControlPlaneEvents } from "./control-plane.mjs";
|
|
10
|
+
import {
|
|
11
|
+
readWaveAssignmentBarrier,
|
|
12
|
+
readWaveDependencyBarrier,
|
|
13
|
+
readRunResultEnvelope,
|
|
14
|
+
} from "./gate-engine.mjs";
|
|
15
|
+
import { buildResumePlan } from "./retry-engine.mjs";
|
|
16
|
+
import { reduceWaveState } from "./wave-state-reducer.mjs";
|
|
17
|
+
import { resolveWaveRoleBindings } from "./role-helpers.mjs";
|
|
18
|
+
import {
|
|
19
|
+
readWaveStateSnapshot,
|
|
20
|
+
writeWaveStateSnapshot,
|
|
21
|
+
} from "./artifact-schemas.mjs";
|
|
22
|
+
import { ensureDirectory } from "./shared.mjs";
|
|
23
|
+
|
|
24
|
+
function normalizeShadowGate(gate) {
|
|
25
|
+
if (!gate || typeof gate !== "object") {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
ok: gate.ok === true,
|
|
30
|
+
agentId: gate.agentId || null,
|
|
31
|
+
componentId: gate.componentId || null,
|
|
32
|
+
statusCode: gate.statusCode || null,
|
|
33
|
+
detail: gate.detail || null,
|
|
34
|
+
waitingOnAgentIds: Array.isArray(gate.waitingOnAgentIds)
|
|
35
|
+
? [...new Set(gate.waitingOnAgentIds.filter(Boolean))].sort()
|
|
36
|
+
: [],
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function normalizeShadowIdList(values) {
|
|
41
|
+
return [...new Set((values || []).filter(Boolean))].sort();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function shadowSlice(compatibility, reducer) {
|
|
45
|
+
return {
|
|
46
|
+
matches: JSON.stringify(compatibility) === JSON.stringify(reducer),
|
|
47
|
+
compatibility,
|
|
48
|
+
reducer,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function contradictionIds(value) {
|
|
53
|
+
if (value instanceof Map) {
|
|
54
|
+
return [...value.keys()];
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
return value.map((entry) => entry?.contradictionId || entry?.id).filter(Boolean);
|
|
58
|
+
}
|
|
59
|
+
if (value && typeof value === "object") {
|
|
60
|
+
return Object.keys(value);
|
|
61
|
+
}
|
|
62
|
+
return [];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function compatibilityBlockerIds(derivedState) {
|
|
66
|
+
const coordinationState = derivedState?.coordinationState || {};
|
|
67
|
+
return normalizeShadowIdList([
|
|
68
|
+
...(coordinationState.blockers || [])
|
|
69
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
70
|
+
.map((record) => record.id),
|
|
71
|
+
...(coordinationState.clarifications || [])
|
|
72
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
73
|
+
.map((record) => record.id),
|
|
74
|
+
...openClarificationLinkedRequests(coordinationState).map((record) => record.id),
|
|
75
|
+
...(coordinationState.humanFeedback || [])
|
|
76
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
77
|
+
.map((record) => record.id),
|
|
78
|
+
...(coordinationState.humanEscalations || [])
|
|
79
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
80
|
+
.map((record) => record.id),
|
|
81
|
+
...((derivedState?.capabilityAssignments || [])
|
|
82
|
+
.filter((assignment) => assignment.blocking)
|
|
83
|
+
.map((assignment) => assignment.requestId || assignment.id)),
|
|
84
|
+
...((derivedState?.dependencySnapshot?.requiredInbound || []).map((record) => record.id)),
|
|
85
|
+
...((derivedState?.dependencySnapshot?.requiredOutbound || []).map((record) => record.id)),
|
|
86
|
+
...((derivedState?.dependencySnapshot?.unresolvedInboundAssignments || []).map((record) => record.id)),
|
|
87
|
+
]);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function buildReducerShadowDiff({
|
|
91
|
+
derivedState,
|
|
92
|
+
compatibilityGateSnapshot = null,
|
|
93
|
+
compatibilityRelaunchResolution = null,
|
|
94
|
+
reducerState,
|
|
95
|
+
resumePlan,
|
|
96
|
+
}) {
|
|
97
|
+
const helperCompatibility = compatibilityGateSnapshot
|
|
98
|
+
? normalizeShadowGate(compatibilityGateSnapshot.helperAssignmentBarrier)
|
|
99
|
+
: normalizeShadowGate(readWaveAssignmentBarrier(derivedState));
|
|
100
|
+
const dependencyCompatibility = compatibilityGateSnapshot
|
|
101
|
+
? normalizeShadowGate(compatibilityGateSnapshot.dependencyBarrier)
|
|
102
|
+
: normalizeShadowGate(readWaveDependencyBarrier(derivedState));
|
|
103
|
+
const overallCompatibility = compatibilityGateSnapshot
|
|
104
|
+
? normalizeShadowGate(compatibilityGateSnapshot.overall)
|
|
105
|
+
: null;
|
|
106
|
+
const retryCompatibility = compatibilityRelaunchResolution
|
|
107
|
+
? {
|
|
108
|
+
selectedAgentIds: normalizeShadowIdList(
|
|
109
|
+
(compatibilityRelaunchResolution.runs || []).map((run) => run.agent.agentId),
|
|
110
|
+
),
|
|
111
|
+
barrier: compatibilityRelaunchResolution.barrier
|
|
112
|
+
? {
|
|
113
|
+
statusCode: compatibilityRelaunchResolution.barrier.statusCode || null,
|
|
114
|
+
detail: compatibilityRelaunchResolution.barrier.detail || null,
|
|
115
|
+
}
|
|
116
|
+
: null,
|
|
117
|
+
}
|
|
118
|
+
: null;
|
|
119
|
+
const blockerCompatibility = compatibilityBlockerIds(derivedState);
|
|
120
|
+
const contradictionCompatibility = normalizeShadowIdList(
|
|
121
|
+
contradictionIds(derivedState?.contradictions),
|
|
122
|
+
);
|
|
123
|
+
const blockerReducer = normalizeShadowIdList(
|
|
124
|
+
(reducerState?.openBlockers || []).map(
|
|
125
|
+
(blocker) => blocker.id || blocker.taskId || blocker.title || blocker.detail,
|
|
126
|
+
),
|
|
127
|
+
);
|
|
128
|
+
const contradictionReducer = normalizeShadowIdList(
|
|
129
|
+
contradictionIds(reducerState?.contradictions),
|
|
130
|
+
);
|
|
131
|
+
const retryReducer = {
|
|
132
|
+
selectedAgentIds: normalizeShadowIdList(
|
|
133
|
+
reducerState?.retryTargetSet?.agentIds || resumePlan?.invalidatedAgentIds || [],
|
|
134
|
+
),
|
|
135
|
+
barrier:
|
|
136
|
+
reducerState?.gateSnapshot?.helperAssignmentBarrier?.ok === false
|
|
137
|
+
? {
|
|
138
|
+
statusCode: reducerState.gateSnapshot.helperAssignmentBarrier.statusCode || null,
|
|
139
|
+
detail: reducerState.gateSnapshot.helperAssignmentBarrier.detail || null,
|
|
140
|
+
}
|
|
141
|
+
: reducerState?.gateSnapshot?.dependencyBarrier?.ok === false
|
|
142
|
+
? {
|
|
143
|
+
statusCode: reducerState.gateSnapshot.dependencyBarrier.statusCode || null,
|
|
144
|
+
detail: reducerState.gateSnapshot.dependencyBarrier.detail || null,
|
|
145
|
+
}
|
|
146
|
+
: null,
|
|
147
|
+
resumeFromPhase: resumePlan?.resumeFromPhase || null,
|
|
148
|
+
};
|
|
149
|
+
const shadowDiff = {
|
|
150
|
+
helperAssignmentBarrier: shadowSlice(
|
|
151
|
+
helperCompatibility,
|
|
152
|
+
normalizeShadowGate(reducerState?.gateSnapshot?.helperAssignmentBarrier),
|
|
153
|
+
),
|
|
154
|
+
dependencyBarrier: shadowSlice(
|
|
155
|
+
dependencyCompatibility,
|
|
156
|
+
normalizeShadowGate(reducerState?.gateSnapshot?.dependencyBarrier),
|
|
157
|
+
),
|
|
158
|
+
overallGate: shadowSlice(
|
|
159
|
+
overallCompatibility,
|
|
160
|
+
normalizeShadowGate(reducerState?.gateSnapshot?.overall),
|
|
161
|
+
),
|
|
162
|
+
blockers: shadowSlice(blockerCompatibility, blockerReducer),
|
|
163
|
+
contradictions: shadowSlice(contradictionCompatibility, contradictionReducer),
|
|
164
|
+
closureReadiness: shadowSlice(
|
|
165
|
+
overallCompatibility
|
|
166
|
+
? { allGatesPass: overallCompatibility.ok === true }
|
|
167
|
+
: null,
|
|
168
|
+
{
|
|
169
|
+
allGatesPass: reducerState?.closureEligibility?.allGatesPass === true,
|
|
170
|
+
waveMayClose: reducerState?.closureEligibility?.waveMayClose === true,
|
|
171
|
+
pendingAgentIds: normalizeShadowIdList(
|
|
172
|
+
reducerState?.closureEligibility?.pendingAgentIds || [],
|
|
173
|
+
),
|
|
174
|
+
},
|
|
175
|
+
),
|
|
176
|
+
retryPlan: shadowSlice(retryCompatibility, retryReducer),
|
|
177
|
+
};
|
|
178
|
+
const comparedSlices = Object.values(shadowDiff).filter(
|
|
179
|
+
(slice) => slice.compatibility !== null && slice.reducer !== null,
|
|
180
|
+
);
|
|
181
|
+
return {
|
|
182
|
+
comparedSliceCount: comparedSlices.length,
|
|
183
|
+
matches: comparedSlices.every((slice) => slice.matches),
|
|
184
|
+
slices: shadowDiff,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export function computeReducerSnapshot({
|
|
189
|
+
lanePaths,
|
|
190
|
+
wave,
|
|
191
|
+
agentRuns,
|
|
192
|
+
derivedState,
|
|
193
|
+
attempt,
|
|
194
|
+
options = {},
|
|
195
|
+
compatibilityGateSnapshot = null,
|
|
196
|
+
compatibilityRelaunchResolution = null,
|
|
197
|
+
}) {
|
|
198
|
+
const agentEnvelopes = {};
|
|
199
|
+
for (const run of agentRuns) {
|
|
200
|
+
const envelopeResult = readRunResultEnvelope(run, wave, { mode: "live" });
|
|
201
|
+
if (envelopeResult?.valid && envelopeResult.envelope) {
|
|
202
|
+
agentEnvelopes[run.agent.agentId] = envelopeResult.envelope;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const controlPlaneLogPath = path.join(
|
|
207
|
+
lanePaths.controlPlaneDir,
|
|
208
|
+
`wave-${wave.wave}.jsonl`,
|
|
209
|
+
);
|
|
210
|
+
const controlPlaneEvents = fs.existsSync(controlPlaneLogPath)
|
|
211
|
+
? readControlPlaneEvents(controlPlaneLogPath)
|
|
212
|
+
: [];
|
|
213
|
+
|
|
214
|
+
const coordinationLogPath = path.join(
|
|
215
|
+
lanePaths.coordinationDir,
|
|
216
|
+
`wave-${wave.wave}.jsonl`,
|
|
217
|
+
);
|
|
218
|
+
const coordinationRecords = fs.existsSync(coordinationLogPath)
|
|
219
|
+
? readMaterializedCoordinationState(coordinationLogPath)
|
|
220
|
+
: null;
|
|
221
|
+
|
|
222
|
+
const feedbackRequests = readWaveHumanFeedbackRequests({
|
|
223
|
+
feedbackRequestsDir: lanePaths.feedbackRequestsDir,
|
|
224
|
+
lane: lanePaths.lane,
|
|
225
|
+
waveNumber: wave.wave,
|
|
226
|
+
agentIds: (agentRuns || []).map((run) => run.agent.agentId),
|
|
227
|
+
orchestratorId: options.orchestratorId,
|
|
228
|
+
});
|
|
229
|
+
const roleBindings = resolveWaveRoleBindings(wave, lanePaths, wave.agents);
|
|
230
|
+
|
|
231
|
+
const reducerState = reduceWaveState({
|
|
232
|
+
controlPlaneEvents,
|
|
233
|
+
coordinationRecords: coordinationRecords?.latestRecords || [],
|
|
234
|
+
agentEnvelopes,
|
|
235
|
+
waveDefinition: wave,
|
|
236
|
+
dependencyTickets: derivedState?.dependencySnapshot || null,
|
|
237
|
+
feedbackRequests: feedbackRequests || [],
|
|
238
|
+
laneConfig: {
|
|
239
|
+
lane: lanePaths.lane,
|
|
240
|
+
contQaAgentId: roleBindings.contQaAgentId,
|
|
241
|
+
contEvalAgentId: roleBindings.contEvalAgentId,
|
|
242
|
+
integrationAgentId: roleBindings.integrationAgentId,
|
|
243
|
+
documentationAgentId: roleBindings.documentationAgentId,
|
|
244
|
+
validationMode: "live",
|
|
245
|
+
evalTargets: wave.evalTargets,
|
|
246
|
+
benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
|
|
247
|
+
laneProfile: lanePaths.laneProfile,
|
|
248
|
+
requireIntegrationStewardFromWave: lanePaths.requireIntegrationStewardFromWave,
|
|
249
|
+
capabilityRouting: lanePaths.capabilityRouting,
|
|
250
|
+
},
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
const resumePlan = buildResumePlan(reducerState, {
|
|
254
|
+
waveDefinition: wave,
|
|
255
|
+
lanePaths,
|
|
256
|
+
});
|
|
257
|
+
const shadowDiff = buildReducerShadowDiff({
|
|
258
|
+
derivedState,
|
|
259
|
+
compatibilityGateSnapshot,
|
|
260
|
+
compatibilityRelaunchResolution,
|
|
261
|
+
reducerState,
|
|
262
|
+
resumePlan,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
const stateDir = path.join(lanePaths.stateDir, "reducer");
|
|
266
|
+
ensureDirectory(stateDir);
|
|
267
|
+
const snapshotPath = path.join(stateDir, `wave-${wave.wave}.json`);
|
|
268
|
+
writeWaveStateSnapshot(
|
|
269
|
+
snapshotPath,
|
|
270
|
+
{
|
|
271
|
+
...reducerState,
|
|
272
|
+
attempt,
|
|
273
|
+
resumePlan,
|
|
274
|
+
shadowDiff,
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
lane: lanePaths.lane,
|
|
278
|
+
wave: wave.wave,
|
|
279
|
+
},
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
reducerState,
|
|
284
|
+
resumePlan,
|
|
285
|
+
shadowDiff,
|
|
286
|
+
snapshotPath,
|
|
287
|
+
};
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
export function readPersistedReducerSnapshot(lanePaths, waveNumber) {
|
|
291
|
+
const stateDir = path.join(lanePaths.stateDir, "reducer");
|
|
292
|
+
const snapshotPath = path.join(stateDir, `wave-${waveNumber}.json`);
|
|
293
|
+
return readWaveStateSnapshot(snapshotPath, {
|
|
294
|
+
lane: lanePaths.lane,
|
|
295
|
+
wave: waveNumber,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { augmentSummaryWithProofRegistry } from "./proof-registry.mjs";
|
|
3
3
|
import { readJsonOrNull } from "./shared.mjs";
|
|
4
|
-
import { buildGateSnapshot } from "./
|
|
4
|
+
import { buildGateSnapshot } from "./gate-engine.mjs";
|
|
5
|
+
import { materializeContradictionsFromControlPlaneEvents } from "./contradiction-entity.mjs";
|
|
5
6
|
import {
|
|
6
7
|
buildQualityMetrics,
|
|
7
8
|
loadTraceBundle,
|
|
@@ -188,6 +189,7 @@ export function replayTraceBundle(dir) {
|
|
|
188
189
|
capabilityAssignments: bundle.capabilityAssignments || [],
|
|
189
190
|
dependencySnapshot: bundle.dependencySnapshot || null,
|
|
190
191
|
integrationSummary: bundle.integrationSummary,
|
|
192
|
+
contradictions: materializeContradictionsFromControlPlaneEvents(bundle.controlPlaneEvents),
|
|
191
193
|
};
|
|
192
194
|
const gateSnapshot = normalizeGateSnapshotForBundle(
|
|
193
195
|
buildGateSnapshot({
|