@chllming/wave-orchestration 0.7.1 → 0.7.2
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 +15 -0
- package/README.md +8 -8
- package/docs/plans/component-cutover-matrix.json +50 -3
- package/docs/plans/current-state.md +1 -1
- package/docs/plans/end-state-architecture.md +927 -0
- package/docs/plans/examples/wave-example-live-proof.md +1 -1
- package/docs/plans/migration.md +2 -2
- package/docs/plans/waves/wave-1.md +376 -0
- package/docs/plans/waves/wave-2.md +292 -0
- package/docs/plans/waves/wave-3.md +342 -0
- package/docs/plans/waves/wave-4.md +391 -0
- package/docs/plans/waves/wave-5.md +382 -0
- package/docs/plans/waves/wave-6.md +321 -0
- package/docs/reference/npmjs-trusted-publishing.md +2 -2
- package/docs/reference/sample-waves.md +4 -4
- package/package.json +1 -1
- package/releases/manifest.json +19 -0
- package/scripts/wave-orchestrator/agent-state.mjs +447 -33
- package/scripts/wave-orchestrator/artifact-schemas.mjs +81 -0
- package/scripts/wave-orchestrator/control-cli.mjs +7 -1
- package/scripts/wave-orchestrator/coordination.mjs +11 -10
- package/scripts/wave-orchestrator/human-input-workflow.mjs +289 -0
- package/scripts/wave-orchestrator/install.mjs +22 -0
- package/scripts/wave-orchestrator/launcher-derived-state.mjs +915 -0
- package/scripts/wave-orchestrator/launcher-gates.mjs +1061 -0
- package/scripts/wave-orchestrator/launcher-retry.mjs +873 -0
- package/scripts/wave-orchestrator/launcher-supervisor.mjs +704 -0
- package/scripts/wave-orchestrator/launcher.mjs +153 -2922
- package/scripts/wave-orchestrator/task-entity.mjs +557 -0
- package/scripts/wave-orchestrator/wave-files.mjs +11 -2
- package/scripts/wave-orchestrator/wave-state-reducer.mjs +566 -0
- package/wave.config.json +1 -1
|
@@ -0,0 +1,915 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import {
|
|
4
|
+
materializeAgentExecutionSummaryForRun,
|
|
5
|
+
materializeAgentExecutionSummaries,
|
|
6
|
+
readRunExecutionSummary,
|
|
7
|
+
} from "./launcher-gates.mjs";
|
|
8
|
+
import {
|
|
9
|
+
isOpenCoordinationStatus,
|
|
10
|
+
appendCoordinationRecord,
|
|
11
|
+
compileAgentInbox,
|
|
12
|
+
compileSharedSummary,
|
|
13
|
+
readMaterializedCoordinationState,
|
|
14
|
+
renderCoordinationBoardProjection,
|
|
15
|
+
updateSeedRecords,
|
|
16
|
+
writeCompiledInbox,
|
|
17
|
+
writeCoordinationBoardProjection,
|
|
18
|
+
writeJsonArtifact,
|
|
19
|
+
buildCoordinationResponseMetrics,
|
|
20
|
+
} from "./coordination-store.mjs";
|
|
21
|
+
import { triageClarificationRequests } from "./clarification-triage.mjs";
|
|
22
|
+
import {
|
|
23
|
+
buildDependencySnapshot,
|
|
24
|
+
buildRequestAssignments,
|
|
25
|
+
renderDependencySnapshotMarkdown,
|
|
26
|
+
syncAssignmentRecords,
|
|
27
|
+
writeDependencySnapshotMarkdown,
|
|
28
|
+
} from "./routing-state.mjs";
|
|
29
|
+
import {
|
|
30
|
+
writeAssignmentSnapshot,
|
|
31
|
+
writeDependencySnapshot,
|
|
32
|
+
} from "./artifact-schemas.mjs";
|
|
33
|
+
import { deriveWaveLedger, readWaveLedger, writeWaveLedger } from "./ledger.mjs";
|
|
34
|
+
import { buildDocsQueue, readDocsQueue, writeDocsQueue } from "./docs-queue.mjs";
|
|
35
|
+
import {
|
|
36
|
+
parseStructuredSignalsFromLog,
|
|
37
|
+
} from "./dashboard-state.mjs";
|
|
38
|
+
import {
|
|
39
|
+
isSecurityReviewAgent,
|
|
40
|
+
resolveSecurityReviewReportPath,
|
|
41
|
+
isContEvalImplementationOwningAgent,
|
|
42
|
+
} from "./role-helpers.mjs";
|
|
43
|
+
import {
|
|
44
|
+
REPO_ROOT,
|
|
45
|
+
compactSingleLine,
|
|
46
|
+
ensureDirectory,
|
|
47
|
+
readJsonOrNull,
|
|
48
|
+
toIsoTimestamp,
|
|
49
|
+
writeTextAtomic,
|
|
50
|
+
} from "./shared.mjs";
|
|
51
|
+
import {
|
|
52
|
+
validateContEvalSummary,
|
|
53
|
+
validateImplementationSummary,
|
|
54
|
+
validateSecuritySummary,
|
|
55
|
+
} from "./agent-state.mjs";
|
|
56
|
+
import {
|
|
57
|
+
applyContext7SelectionsToWave,
|
|
58
|
+
describeContext7Libraries,
|
|
59
|
+
loadContext7BundleIndex,
|
|
60
|
+
} from "./context7.mjs";
|
|
61
|
+
|
|
62
|
+
export function waveCoordinationLogPath(lanePaths, waveNumber) {
|
|
63
|
+
return path.join(lanePaths.coordinationDir, `wave-${waveNumber}.jsonl`);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function waveInboxDir(lanePaths, waveNumber) {
|
|
67
|
+
return path.join(lanePaths.inboxesDir, `wave-${waveNumber}`);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
export function waveAssignmentsPath(lanePaths, waveNumber) {
|
|
71
|
+
return path.join(lanePaths.assignmentsDir, `wave-${waveNumber}.json`);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function waveLedgerPath(lanePaths, waveNumber) {
|
|
75
|
+
return path.join(lanePaths.ledgerDir, `wave-${waveNumber}.json`);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function waveDependencySnapshotPath(lanePaths, waveNumber) {
|
|
79
|
+
return path.join(lanePaths.dependencySnapshotsDir, `wave-${waveNumber}.json`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function waveDependencySnapshotMarkdownPath(lanePaths, waveNumber) {
|
|
83
|
+
return path.join(lanePaths.dependencySnapshotsDir, `wave-${waveNumber}.md`);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export function waveDocsQueuePath(lanePaths, waveNumber) {
|
|
87
|
+
return path.join(lanePaths.docsQueueDir, `wave-${waveNumber}.json`);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function waveIntegrationPath(lanePaths, waveNumber) {
|
|
91
|
+
return path.join(lanePaths.integrationDir, `wave-${waveNumber}.json`);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function waveIntegrationMarkdownPath(lanePaths, waveNumber) {
|
|
95
|
+
return path.join(lanePaths.integrationDir, `wave-${waveNumber}.md`);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function waveSecurityPath(lanePaths, waveNumber) {
|
|
99
|
+
return path.join(lanePaths.securityDir, `wave-${waveNumber}.json`);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export function waveSecurityMarkdownPath(lanePaths, waveNumber) {
|
|
103
|
+
return path.join(lanePaths.securityDir, `wave-${waveNumber}.md`);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function uniqueStringEntries(values) {
|
|
107
|
+
return Array.from(
|
|
108
|
+
new Set(
|
|
109
|
+
(Array.isArray(values) ? values : [])
|
|
110
|
+
.map((value) => String(value || "").trim())
|
|
111
|
+
.filter(Boolean),
|
|
112
|
+
),
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function summarizeIntegrationRecord(record, options = {}) {
|
|
117
|
+
const summary = compactSingleLine(
|
|
118
|
+
record?.summary || record?.detail || record?.kind || "coordination item",
|
|
119
|
+
options.maxChars || 180,
|
|
120
|
+
);
|
|
121
|
+
return `${record.id}: ${summary}`;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function summarizeDocsQueueItem(item) {
|
|
125
|
+
return `${item.id}: ${compactSingleLine(item.summary || item.path || item.detail || "documentation update required", 180)}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function summarizeGap(agentId, detail, fallback) {
|
|
129
|
+
return `${agentId}: ${compactSingleLine(detail || fallback, 180)}`;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function textMentionsAnyKeyword(value, keywords) {
|
|
133
|
+
const text = String(value || "").trim().toLowerCase();
|
|
134
|
+
if (!text) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
return keywords.some((keyword) => text.includes(String(keyword || "").trim().toLowerCase()));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function actionableIntegrationRecords(coordinationState) {
|
|
141
|
+
return (coordinationState?.latestRecords || []).filter(
|
|
142
|
+
(record) =>
|
|
143
|
+
!["cancelled", "superseded"].includes(String(record?.status || "").trim().toLowerCase()) &&
|
|
144
|
+
![
|
|
145
|
+
"human-feedback",
|
|
146
|
+
"human-escalation",
|
|
147
|
+
"orchestrator-guidance",
|
|
148
|
+
"resolved-by-policy",
|
|
149
|
+
"integration-summary",
|
|
150
|
+
].includes(record?.kind),
|
|
151
|
+
);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function normalizeOwnedReference(value) {
|
|
155
|
+
return String(value || "").trim().replace(/\/+$/, "");
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function matchesOwnedPathArtifact(artifactRef, ownedPath) {
|
|
159
|
+
const normalizedArtifact = normalizeOwnedReference(artifactRef);
|
|
160
|
+
const normalizedOwnedPath = normalizeOwnedReference(ownedPath);
|
|
161
|
+
if (!normalizedArtifact || !normalizedOwnedPath) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return (
|
|
165
|
+
normalizedArtifact === normalizedOwnedPath ||
|
|
166
|
+
normalizedArtifact.startsWith(`${normalizedOwnedPath}/`)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function resolveArtifactOwners(artifactRef, agents) {
|
|
171
|
+
const owners = [];
|
|
172
|
+
const normalizedArtifact = normalizeOwnedReference(artifactRef);
|
|
173
|
+
if (!normalizedArtifact) {
|
|
174
|
+
return owners;
|
|
175
|
+
}
|
|
176
|
+
for (const agent of agents || []) {
|
|
177
|
+
const ownedComponents = Array.isArray(agent?.components) ? agent.components : [];
|
|
178
|
+
const ownedPaths = Array.isArray(agent?.ownedPaths) ? agent.ownedPaths : [];
|
|
179
|
+
if (
|
|
180
|
+
ownedComponents.some((componentId) => normalizeOwnedReference(componentId) === normalizedArtifact) ||
|
|
181
|
+
ownedPaths.some((ownedPath) => matchesOwnedPathArtifact(normalizedArtifact, ownedPath))
|
|
182
|
+
) {
|
|
183
|
+
owners.push(agent.agentId);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
return owners;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function inferIntegrationRecommendation(evidence) {
|
|
190
|
+
if ((evidence.unresolvedBlockers || []).length > 0) {
|
|
191
|
+
return {
|
|
192
|
+
recommendation: "needs-more-work",
|
|
193
|
+
detail: `${evidence.unresolvedBlockers.length} unresolved blocker(s) remain.`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
if ((evidence.conflictingClaims || []).length > 0) {
|
|
197
|
+
return {
|
|
198
|
+
recommendation: "needs-more-work",
|
|
199
|
+
detail: `${evidence.conflictingClaims.length} conflicting claim(s) remain.`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
if ((evidence.proofGaps || []).length > 0) {
|
|
203
|
+
return {
|
|
204
|
+
recommendation: "needs-more-work",
|
|
205
|
+
detail: `${evidence.proofGaps.length} proof gap(s) remain.`,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
if ((evidence.deployRisks || []).length > 0) {
|
|
209
|
+
return {
|
|
210
|
+
recommendation: "needs-more-work",
|
|
211
|
+
detail: `${evidence.deployRisks.length} deploy or ops risk(s) remain.`,
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
return {
|
|
215
|
+
recommendation: "ready-for-doc-closure",
|
|
216
|
+
detail:
|
|
217
|
+
"No unresolved blockers, contradictions, proof gaps, or deploy risks remain in integration state.",
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export function buildWaveSecuritySummary({
|
|
222
|
+
lanePaths,
|
|
223
|
+
wave,
|
|
224
|
+
attempt,
|
|
225
|
+
summariesByAgentId = {},
|
|
226
|
+
}) {
|
|
227
|
+
const createdAt = toIsoTimestamp();
|
|
228
|
+
const securityAgents = (wave.agents || []).filter((agent) => isSecurityReviewAgent(agent));
|
|
229
|
+
if (securityAgents.length === 0) {
|
|
230
|
+
return {
|
|
231
|
+
wave: wave.wave,
|
|
232
|
+
lane: lanePaths.lane,
|
|
233
|
+
attempt,
|
|
234
|
+
overallState: "not-applicable",
|
|
235
|
+
totalFindings: 0,
|
|
236
|
+
totalApprovals: 0,
|
|
237
|
+
concernAgentIds: [],
|
|
238
|
+
blockedAgentIds: [],
|
|
239
|
+
detail: "No security reviewer declared for this wave.",
|
|
240
|
+
agents: [],
|
|
241
|
+
createdAt,
|
|
242
|
+
updatedAt: createdAt,
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
const agents = securityAgents.map((agent) => {
|
|
246
|
+
const summary = summariesByAgentId?.[agent.agentId] || null;
|
|
247
|
+
const validation = validateSecuritySummary(agent, summary);
|
|
248
|
+
const explicitState = summary?.security?.state || null;
|
|
249
|
+
return {
|
|
250
|
+
agentId: agent.agentId,
|
|
251
|
+
title: agent.title || agent.agentId,
|
|
252
|
+
state: validation.ok
|
|
253
|
+
? explicitState || "clear"
|
|
254
|
+
: explicitState === "blocked"
|
|
255
|
+
? "blocked"
|
|
256
|
+
: "pending",
|
|
257
|
+
findings: summary?.security?.findings || 0,
|
|
258
|
+
approvals: summary?.security?.approvals || 0,
|
|
259
|
+
detail: validation.ok
|
|
260
|
+
? summary?.security?.detail || validation.detail || ""
|
|
261
|
+
: validation.detail,
|
|
262
|
+
reportPath: summary?.reportPath || resolveSecurityReviewReportPath(agent) || null,
|
|
263
|
+
statusCode: validation.statusCode,
|
|
264
|
+
ok: validation.ok,
|
|
265
|
+
};
|
|
266
|
+
});
|
|
267
|
+
const blockedAgentIds = agents
|
|
268
|
+
.filter((entry) => entry.state === "blocked")
|
|
269
|
+
.map((entry) => entry.agentId);
|
|
270
|
+
const concernAgentIds = agents
|
|
271
|
+
.filter((entry) => entry.state === "concerns")
|
|
272
|
+
.map((entry) => entry.agentId);
|
|
273
|
+
const pendingAgentIds = agents
|
|
274
|
+
.filter((entry) => entry.state === "pending")
|
|
275
|
+
.map((entry) => entry.agentId);
|
|
276
|
+
const overallState =
|
|
277
|
+
blockedAgentIds.length > 0
|
|
278
|
+
? "blocked"
|
|
279
|
+
: pendingAgentIds.length > 0
|
|
280
|
+
? "pending"
|
|
281
|
+
: concernAgentIds.length > 0
|
|
282
|
+
? "concerns"
|
|
283
|
+
: "clear";
|
|
284
|
+
const totalFindings = agents.reduce((sum, entry) => sum + (entry.findings || 0), 0);
|
|
285
|
+
const totalApprovals = agents.reduce((sum, entry) => sum + (entry.approvals || 0), 0);
|
|
286
|
+
const detail =
|
|
287
|
+
overallState === "blocked"
|
|
288
|
+
? `Security review blocked by ${blockedAgentIds.join(", ")}.`
|
|
289
|
+
: overallState === "pending"
|
|
290
|
+
? `Security review output is incomplete for ${pendingAgentIds.join(", ")}.`
|
|
291
|
+
: overallState === "concerns"
|
|
292
|
+
? `Security review reported advisory concerns from ${concernAgentIds.join(", ")}.`
|
|
293
|
+
: "Security review is clear.";
|
|
294
|
+
return {
|
|
295
|
+
wave: wave.wave,
|
|
296
|
+
lane: lanePaths.lane,
|
|
297
|
+
attempt,
|
|
298
|
+
overallState,
|
|
299
|
+
totalFindings,
|
|
300
|
+
totalApprovals,
|
|
301
|
+
concernAgentIds,
|
|
302
|
+
blockedAgentIds,
|
|
303
|
+
detail,
|
|
304
|
+
agents,
|
|
305
|
+
createdAt,
|
|
306
|
+
updatedAt: createdAt,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function renderWaveSecuritySummaryMarkdown(securitySummary) {
|
|
311
|
+
return [
|
|
312
|
+
`# Wave ${securitySummary.wave} Security Summary`,
|
|
313
|
+
"",
|
|
314
|
+
`- State: ${securitySummary.overallState || "unknown"}`,
|
|
315
|
+
`- Detail: ${securitySummary.detail || "n/a"}`,
|
|
316
|
+
`- Total findings: ${securitySummary.totalFindings || 0}`,
|
|
317
|
+
`- Total approvals: ${securitySummary.totalApprovals || 0}`,
|
|
318
|
+
`- Reviewers: ${(securitySummary.agents || []).length}`,
|
|
319
|
+
"",
|
|
320
|
+
"## Reviews",
|
|
321
|
+
...((securitySummary.agents || []).length > 0
|
|
322
|
+
? securitySummary.agents.map(
|
|
323
|
+
(entry) =>
|
|
324
|
+
`- ${entry.agentId}: state=${entry.state || "unknown"} findings=${entry.findings || 0} approvals=${entry.approvals || 0}${entry.reportPath ? ` report=${entry.reportPath}` : ""}${entry.detail ? ` detail=${entry.detail}` : ""}`,
|
|
325
|
+
)
|
|
326
|
+
: ["- None."]),
|
|
327
|
+
"",
|
|
328
|
+
].join("\n");
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function padReportedEntries(entries, minimumCount, label) {
|
|
332
|
+
const padded = [...entries];
|
|
333
|
+
for (let index = padded.length + 1; index <= minimumCount; index += 1) {
|
|
334
|
+
padded.push(`${label} #${index}`);
|
|
335
|
+
}
|
|
336
|
+
return padded;
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function buildIntegrationEvidence({
|
|
340
|
+
lanePaths,
|
|
341
|
+
wave,
|
|
342
|
+
coordinationState,
|
|
343
|
+
summariesByAgentId,
|
|
344
|
+
docsQueue,
|
|
345
|
+
agentRuns,
|
|
346
|
+
dependencySnapshot = null,
|
|
347
|
+
capabilityAssignments = [],
|
|
348
|
+
securitySummary = null,
|
|
349
|
+
}) {
|
|
350
|
+
const openClaims = (coordinationState?.claims || [])
|
|
351
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
352
|
+
.map((record) => summarizeIntegrationRecord(record));
|
|
353
|
+
const conflictingClaims = (coordinationState?.claims || [])
|
|
354
|
+
.filter(
|
|
355
|
+
(record) =>
|
|
356
|
+
isOpenCoordinationStatus(record.status) &&
|
|
357
|
+
/conflict|contradict/i.test(`${record.summary || ""}\n${record.detail || ""}`),
|
|
358
|
+
)
|
|
359
|
+
.map((record) => summarizeIntegrationRecord(record));
|
|
360
|
+
const unresolvedBlockers = (coordinationState?.blockers || [])
|
|
361
|
+
.filter((record) => isOpenCoordinationStatus(record.status))
|
|
362
|
+
.map((record) => summarizeIntegrationRecord(record));
|
|
363
|
+
|
|
364
|
+
const interfaceKeywords = ["interface", "contract", "api", "schema", "migration", "signature"];
|
|
365
|
+
const changedInterfaces = actionableIntegrationRecords(coordinationState)
|
|
366
|
+
.filter((record) =>
|
|
367
|
+
textMentionsAnyKeyword(
|
|
368
|
+
[record.summary, record.detail, ...(record.artifactRefs || [])].join("\n"),
|
|
369
|
+
interfaceKeywords,
|
|
370
|
+
),
|
|
371
|
+
)
|
|
372
|
+
.map((record) => summarizeIntegrationRecord(record));
|
|
373
|
+
|
|
374
|
+
const crossComponentImpacts = actionableIntegrationRecords(coordinationState)
|
|
375
|
+
.flatMap((record) => {
|
|
376
|
+
const owners = new Set();
|
|
377
|
+
for (const artifactRef of record.artifactRefs || []) {
|
|
378
|
+
for (const owner of resolveArtifactOwners(artifactRef, wave.agents)) {
|
|
379
|
+
owners.add(owner);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
for (const target of record.targets || []) {
|
|
383
|
+
if (String(target).startsWith("agent:")) {
|
|
384
|
+
owners.add(String(target).slice("agent:".length));
|
|
385
|
+
} else if ((wave.agents || []).some((agent) => agent.agentId === target)) {
|
|
386
|
+
owners.add(String(target));
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
if (owners.size <= 1) {
|
|
390
|
+
return [];
|
|
391
|
+
}
|
|
392
|
+
return [
|
|
393
|
+
`${summarizeIntegrationRecord(record)} [owners: ${Array.from(owners).toSorted().join(", ")}]`,
|
|
394
|
+
];
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
const proofGapEntries = [];
|
|
398
|
+
const docGapEntries = Array.isArray(docsQueue?.items)
|
|
399
|
+
? docsQueue.items.map((item) => summarizeDocsQueueItem(item))
|
|
400
|
+
: [];
|
|
401
|
+
const deployRiskEntries = [];
|
|
402
|
+
const securityFindingEntries = [];
|
|
403
|
+
const securityApprovalEntries = [];
|
|
404
|
+
for (const agent of wave.agents || []) {
|
|
405
|
+
const summary = summariesByAgentId?.[agent.agentId] || null;
|
|
406
|
+
const contEvalImplementationOwning =
|
|
407
|
+
agent.agentId === lanePaths.contEvalAgentId &&
|
|
408
|
+
isContEvalImplementationOwningAgent(agent, {
|
|
409
|
+
contEvalAgentId: lanePaths.contEvalAgentId,
|
|
410
|
+
});
|
|
411
|
+
if (isSecurityReviewAgent(agent)) {
|
|
412
|
+
continue;
|
|
413
|
+
}
|
|
414
|
+
if (agent.agentId === lanePaths.contEvalAgentId) {
|
|
415
|
+
const validation = validateContEvalSummary(agent, summary, {
|
|
416
|
+
mode: "live",
|
|
417
|
+
evalTargets: wave.evalTargets,
|
|
418
|
+
benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
|
|
419
|
+
});
|
|
420
|
+
if (!validation.ok) {
|
|
421
|
+
proofGapEntries.push(
|
|
422
|
+
summarizeGap(agent.agentId, validation.detail, "cont-EVAL target is not yet satisfied."),
|
|
423
|
+
);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (
|
|
427
|
+
![
|
|
428
|
+
lanePaths.contQaAgentId,
|
|
429
|
+
lanePaths.integrationAgentId,
|
|
430
|
+
lanePaths.documentationAgentId,
|
|
431
|
+
].includes(agent.agentId) &&
|
|
432
|
+
(agent.agentId !== lanePaths.contEvalAgentId || contEvalImplementationOwning)
|
|
433
|
+
) {
|
|
434
|
+
const validation = validateImplementationSummary(agent, summary);
|
|
435
|
+
if (!validation.ok) {
|
|
436
|
+
const entry = summarizeGap(agent.agentId, validation.detail, "Implementation validation failed.");
|
|
437
|
+
if (["missing-doc-delta", "doc-impact-gap", "invalid-doc-delta-format"].includes(validation.statusCode)) {
|
|
438
|
+
docGapEntries.push(entry);
|
|
439
|
+
} else {
|
|
440
|
+
proofGapEntries.push(entry);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
for (const gap of summary?.gaps || []) {
|
|
445
|
+
const entry = summarizeGap(
|
|
446
|
+
agent.agentId,
|
|
447
|
+
gap.detail,
|
|
448
|
+
`${gap.kind || "unknown"} gap reported.`,
|
|
449
|
+
);
|
|
450
|
+
if (gap.kind === "docs") {
|
|
451
|
+
docGapEntries.push(entry);
|
|
452
|
+
} else if (gap.kind === "ops") {
|
|
453
|
+
deployRiskEntries.push(entry);
|
|
454
|
+
} else {
|
|
455
|
+
proofGapEntries.push(entry);
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
for (const run of agentRuns || []) {
|
|
461
|
+
const signals = parseStructuredSignalsFromLog(run.logPath);
|
|
462
|
+
if (signals?.deployment && signals.deployment.state !== "healthy") {
|
|
463
|
+
deployRiskEntries.push(
|
|
464
|
+
summarizeGap(
|
|
465
|
+
run.agent.agentId,
|
|
466
|
+
`Deployment ${signals.deployment.service} ended in state ${signals.deployment.state}${signals.deployment.detail ? ` (${signals.deployment.detail})` : ""}.`,
|
|
467
|
+
"Deployment did not finish healthy.",
|
|
468
|
+
),
|
|
469
|
+
);
|
|
470
|
+
}
|
|
471
|
+
if (
|
|
472
|
+
signals?.infra &&
|
|
473
|
+
!["conformant", "action-complete"].includes(
|
|
474
|
+
String(signals.infra.state || "").trim().toLowerCase(),
|
|
475
|
+
)
|
|
476
|
+
) {
|
|
477
|
+
deployRiskEntries.push(
|
|
478
|
+
summarizeGap(
|
|
479
|
+
run.agent.agentId,
|
|
480
|
+
`Infra ${signals.infra.kind || "unknown"} on ${signals.infra.target || "unknown"} ended in state ${signals.infra.state || "unknown"}${signals.infra.detail ? ` (${signals.infra.detail})` : ""}.`,
|
|
481
|
+
"Infra risk remains open.",
|
|
482
|
+
),
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const inboundDependencies = (dependencySnapshot?.openInbound || []).map(
|
|
488
|
+
(record) =>
|
|
489
|
+
`${record.id}: ${compactSingleLine(record.summary || record.detail || "inbound dependency", 180)}${record.assignedAgentId ? ` -> ${record.assignedAgentId}` : ""}`,
|
|
490
|
+
);
|
|
491
|
+
const outboundDependencies = (dependencySnapshot?.openOutbound || []).map(
|
|
492
|
+
(record) =>
|
|
493
|
+
`${record.id}: ${compactSingleLine(record.summary || record.detail || "outbound dependency", 180)}`,
|
|
494
|
+
);
|
|
495
|
+
const helperAssignments = (capabilityAssignments || [])
|
|
496
|
+
.filter((assignment) => assignment.blocking)
|
|
497
|
+
.map(
|
|
498
|
+
(assignment) =>
|
|
499
|
+
`${assignment.requestId}: ${assignment.target}${assignment.assignedAgentId ? ` -> ${assignment.assignedAgentId}` : " -> unresolved"} (${assignment.assignmentReason || "n/a"})`,
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
for (const review of securitySummary?.agents || []) {
|
|
503
|
+
if (review.state === "blocked" || review.state === "concerns") {
|
|
504
|
+
securityFindingEntries.push(
|
|
505
|
+
summarizeGap(
|
|
506
|
+
review.agentId,
|
|
507
|
+
review.detail,
|
|
508
|
+
review.state === "blocked"
|
|
509
|
+
? "Security review blocked the wave."
|
|
510
|
+
: "Security review reported advisory concerns.",
|
|
511
|
+
),
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
if ((review.approvals || 0) > 0) {
|
|
515
|
+
securityApprovalEntries.push(
|
|
516
|
+
summarizeGap(
|
|
517
|
+
review.agentId,
|
|
518
|
+
review.detail,
|
|
519
|
+
`${review.approvals} security approval(s) remain open.`,
|
|
520
|
+
),
|
|
521
|
+
);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
return {
|
|
526
|
+
openClaims: uniqueStringEntries(openClaims),
|
|
527
|
+
conflictingClaims: uniqueStringEntries(conflictingClaims),
|
|
528
|
+
unresolvedBlockers: uniqueStringEntries(unresolvedBlockers),
|
|
529
|
+
changedInterfaces: uniqueStringEntries(changedInterfaces),
|
|
530
|
+
crossComponentImpacts: uniqueStringEntries(crossComponentImpacts),
|
|
531
|
+
proofGaps: uniqueStringEntries(proofGapEntries),
|
|
532
|
+
docGaps: uniqueStringEntries(docGapEntries),
|
|
533
|
+
deployRisks: uniqueStringEntries(deployRiskEntries),
|
|
534
|
+
inboundDependencies: uniqueStringEntries(inboundDependencies),
|
|
535
|
+
outboundDependencies: uniqueStringEntries(outboundDependencies),
|
|
536
|
+
helperAssignments: uniqueStringEntries(helperAssignments),
|
|
537
|
+
securityState: securitySummary?.overallState || "not-applicable",
|
|
538
|
+
securityFindings: uniqueStringEntries(securityFindingEntries),
|
|
539
|
+
securityApprovals: uniqueStringEntries(securityApprovalEntries),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export function buildWaveIntegrationSummary({
|
|
544
|
+
lanePaths,
|
|
545
|
+
wave,
|
|
546
|
+
attempt,
|
|
547
|
+
coordinationState,
|
|
548
|
+
summariesByAgentId,
|
|
549
|
+
docsQueue,
|
|
550
|
+
runtimeAssignments,
|
|
551
|
+
agentRuns,
|
|
552
|
+
capabilityAssignments = [],
|
|
553
|
+
dependencySnapshot = null,
|
|
554
|
+
securitySummary = null,
|
|
555
|
+
}) {
|
|
556
|
+
const explicitIntegration = summariesByAgentId[lanePaths.integrationAgentId]?.integration || null;
|
|
557
|
+
const evidence = buildIntegrationEvidence({
|
|
558
|
+
lanePaths,
|
|
559
|
+
wave,
|
|
560
|
+
coordinationState,
|
|
561
|
+
summariesByAgentId,
|
|
562
|
+
docsQueue,
|
|
563
|
+
agentRuns,
|
|
564
|
+
capabilityAssignments,
|
|
565
|
+
dependencySnapshot,
|
|
566
|
+
securitySummary,
|
|
567
|
+
});
|
|
568
|
+
if (explicitIntegration) {
|
|
569
|
+
return {
|
|
570
|
+
wave: wave.wave,
|
|
571
|
+
lane: lanePaths.lane,
|
|
572
|
+
agentId: lanePaths.integrationAgentId,
|
|
573
|
+
attempt,
|
|
574
|
+
openClaims: padReportedEntries(
|
|
575
|
+
evidence.openClaims,
|
|
576
|
+
explicitIntegration.claims || 0,
|
|
577
|
+
"Integration steward reported unresolved claim",
|
|
578
|
+
),
|
|
579
|
+
conflictingClaims: padReportedEntries(
|
|
580
|
+
evidence.conflictingClaims,
|
|
581
|
+
explicitIntegration.conflicts || 0,
|
|
582
|
+
"Integration steward reported unresolved conflict",
|
|
583
|
+
),
|
|
584
|
+
unresolvedBlockers: padReportedEntries(
|
|
585
|
+
evidence.unresolvedBlockers,
|
|
586
|
+
explicitIntegration.blockers || 0,
|
|
587
|
+
"Integration steward reported unresolved blocker",
|
|
588
|
+
),
|
|
589
|
+
changedInterfaces: evidence.changedInterfaces,
|
|
590
|
+
crossComponentImpacts: evidence.crossComponentImpacts,
|
|
591
|
+
proofGaps: evidence.proofGaps,
|
|
592
|
+
docGaps: evidence.docGaps,
|
|
593
|
+
deployRisks: evidence.deployRisks,
|
|
594
|
+
securityState: evidence.securityState,
|
|
595
|
+
securityFindings: evidence.securityFindings,
|
|
596
|
+
securityApprovals: evidence.securityApprovals,
|
|
597
|
+
inboundDependencies: evidence.inboundDependencies,
|
|
598
|
+
outboundDependencies: evidence.outboundDependencies,
|
|
599
|
+
helperAssignments: evidence.helperAssignments,
|
|
600
|
+
runtimeAssignments,
|
|
601
|
+
recommendation: explicitIntegration.state,
|
|
602
|
+
detail: explicitIntegration.detail || "",
|
|
603
|
+
createdAt: toIsoTimestamp(),
|
|
604
|
+
updatedAt: toIsoTimestamp(),
|
|
605
|
+
};
|
|
606
|
+
}
|
|
607
|
+
const inferred = inferIntegrationRecommendation(evidence);
|
|
608
|
+
return {
|
|
609
|
+
wave: wave.wave,
|
|
610
|
+
lane: lanePaths.lane,
|
|
611
|
+
agentId: "launcher",
|
|
612
|
+
attempt,
|
|
613
|
+
...evidence,
|
|
614
|
+
runtimeAssignments,
|
|
615
|
+
recommendation: inferred.recommendation,
|
|
616
|
+
detail: inferred.detail,
|
|
617
|
+
createdAt: toIsoTimestamp(),
|
|
618
|
+
updatedAt: toIsoTimestamp(),
|
|
619
|
+
};
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
function renderIntegrationSection(title, items) {
|
|
623
|
+
return [
|
|
624
|
+
title,
|
|
625
|
+
...((items || []).length > 0 ? items.map((item) => `- ${item}`) : ["- None."]),
|
|
626
|
+
"",
|
|
627
|
+
];
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
function renderIntegrationSummaryMarkdown(integrationSummary) {
|
|
631
|
+
return [
|
|
632
|
+
`# Wave ${integrationSummary.wave} Integration Summary`,
|
|
633
|
+
"",
|
|
634
|
+
`- Recommendation: ${integrationSummary.recommendation || "unknown"}`,
|
|
635
|
+
`- Detail: ${integrationSummary.detail || "n/a"}`,
|
|
636
|
+
`- Open claims: ${(integrationSummary.openClaims || []).length}`,
|
|
637
|
+
`- Conflicting claims: ${(integrationSummary.conflictingClaims || []).length}`,
|
|
638
|
+
`- Unresolved blockers: ${(integrationSummary.unresolvedBlockers || []).length}`,
|
|
639
|
+
`- Changed interfaces: ${(integrationSummary.changedInterfaces || []).length}`,
|
|
640
|
+
`- Cross-component impacts: ${(integrationSummary.crossComponentImpacts || []).length}`,
|
|
641
|
+
`- Proof gaps: ${(integrationSummary.proofGaps || []).length}`,
|
|
642
|
+
`- Deploy risks: ${(integrationSummary.deployRisks || []).length}`,
|
|
643
|
+
`- Documentation gaps: ${(integrationSummary.docGaps || []).length}`,
|
|
644
|
+
`- Security review: ${integrationSummary.securityState || "not-applicable"}`,
|
|
645
|
+
`- Security findings: ${(integrationSummary.securityFindings || []).length}`,
|
|
646
|
+
`- Security approvals: ${(integrationSummary.securityApprovals || []).length}`,
|
|
647
|
+
`- Inbound dependencies: ${(integrationSummary.inboundDependencies || []).length}`,
|
|
648
|
+
`- Outbound dependencies: ${(integrationSummary.outboundDependencies || []).length}`,
|
|
649
|
+
`- Helper assignments: ${(integrationSummary.helperAssignments || []).length}`,
|
|
650
|
+
"",
|
|
651
|
+
...renderIntegrationSection("## Open Claims", integrationSummary.openClaims),
|
|
652
|
+
...renderIntegrationSection("## Conflicting Claims", integrationSummary.conflictingClaims),
|
|
653
|
+
...renderIntegrationSection("## Unresolved Blockers", integrationSummary.unresolvedBlockers),
|
|
654
|
+
...renderIntegrationSection("## Changed Interfaces", integrationSummary.changedInterfaces),
|
|
655
|
+
...renderIntegrationSection(
|
|
656
|
+
"## Cross-Component Impacts",
|
|
657
|
+
integrationSummary.crossComponentImpacts,
|
|
658
|
+
),
|
|
659
|
+
...renderIntegrationSection("## Proof Gaps", integrationSummary.proofGaps),
|
|
660
|
+
...renderIntegrationSection("## Deploy Risks", integrationSummary.deployRisks),
|
|
661
|
+
...renderIntegrationSection("## Security Findings", integrationSummary.securityFindings),
|
|
662
|
+
...renderIntegrationSection("## Security Approvals", integrationSummary.securityApprovals),
|
|
663
|
+
...renderIntegrationSection("## Inbound Dependencies", integrationSummary.inboundDependencies),
|
|
664
|
+
...renderIntegrationSection("## Outbound Dependencies", integrationSummary.outboundDependencies),
|
|
665
|
+
...renderIntegrationSection("## Helper Assignments", integrationSummary.helperAssignments),
|
|
666
|
+
"## Runtime Assignments",
|
|
667
|
+
...((integrationSummary.runtimeAssignments || []).length > 0
|
|
668
|
+
? integrationSummary.runtimeAssignments.map(
|
|
669
|
+
(assignment) =>
|
|
670
|
+
`- ${assignment.agentId}: executor=${assignment.executorId || "n/a"} role=${assignment.role || "n/a"} profile=${assignment.profile || "none"} fallback_used=${assignment.fallbackUsed ? "yes" : "no"}`,
|
|
671
|
+
)
|
|
672
|
+
: ["- None."]),
|
|
673
|
+
"",
|
|
674
|
+
...renderIntegrationSection("## Documentation Gaps", integrationSummary.docGaps),
|
|
675
|
+
].join("\n");
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
export function writeWaveDerivedState({
|
|
679
|
+
lanePaths,
|
|
680
|
+
wave,
|
|
681
|
+
agentRuns = [],
|
|
682
|
+
summariesByAgentId = {},
|
|
683
|
+
feedbackRequests = [],
|
|
684
|
+
attempt = 0,
|
|
685
|
+
orchestratorId = null,
|
|
686
|
+
}) {
|
|
687
|
+
const coordinationLogPath = waveCoordinationLogPath(lanePaths, wave.wave);
|
|
688
|
+
const existingDocsQueue = readDocsQueue(waveDocsQueuePath(lanePaths, wave.wave));
|
|
689
|
+
const existingIntegrationSummary = readJsonOrNull(waveIntegrationPath(lanePaths, wave.wave));
|
|
690
|
+
const existingLedger = readWaveLedger(waveLedgerPath(lanePaths, wave.wave));
|
|
691
|
+
updateSeedRecords(coordinationLogPath, {
|
|
692
|
+
lane: lanePaths.lane,
|
|
693
|
+
wave: wave.wave,
|
|
694
|
+
agents: wave.agents,
|
|
695
|
+
componentPromotions: wave.componentPromotions,
|
|
696
|
+
sharedPlanDocs: lanePaths.sharedPlanDocs,
|
|
697
|
+
contQaAgentId: lanePaths.contQaAgentId,
|
|
698
|
+
contEvalAgentId: lanePaths.contEvalAgentId,
|
|
699
|
+
integrationAgentId: lanePaths.integrationAgentId,
|
|
700
|
+
documentationAgentId: lanePaths.documentationAgentId,
|
|
701
|
+
feedbackRequests,
|
|
702
|
+
});
|
|
703
|
+
let coordinationState = readMaterializedCoordinationState(coordinationLogPath);
|
|
704
|
+
const clarificationTriage = triageClarificationRequests({
|
|
705
|
+
lanePaths,
|
|
706
|
+
wave,
|
|
707
|
+
coordinationLogPath,
|
|
708
|
+
coordinationState,
|
|
709
|
+
orchestratorId,
|
|
710
|
+
attempt,
|
|
711
|
+
resolutionContext: {
|
|
712
|
+
docsQueue: existingDocsQueue,
|
|
713
|
+
integrationSummary: existingIntegrationSummary,
|
|
714
|
+
ledger: existingLedger,
|
|
715
|
+
summariesByAgentId,
|
|
716
|
+
},
|
|
717
|
+
});
|
|
718
|
+
if (clarificationTriage.changed) {
|
|
719
|
+
coordinationState = readMaterializedCoordinationState(coordinationLogPath);
|
|
720
|
+
}
|
|
721
|
+
const capabilityAssignments = buildRequestAssignments({
|
|
722
|
+
coordinationState,
|
|
723
|
+
agents: wave.agents,
|
|
724
|
+
ledger: existingLedger,
|
|
725
|
+
capabilityRouting: lanePaths.capabilityRouting,
|
|
726
|
+
});
|
|
727
|
+
syncAssignmentRecords(coordinationLogPath, {
|
|
728
|
+
lane: lanePaths.lane,
|
|
729
|
+
wave: wave.wave,
|
|
730
|
+
assignments: capabilityAssignments,
|
|
731
|
+
});
|
|
732
|
+
coordinationState = readMaterializedCoordinationState(coordinationLogPath);
|
|
733
|
+
const dependencySnapshot = buildDependencySnapshot({
|
|
734
|
+
dirPath: lanePaths.crossLaneDependenciesDir,
|
|
735
|
+
lane: lanePaths.lane,
|
|
736
|
+
waveNumber: wave.wave,
|
|
737
|
+
agents: wave.agents,
|
|
738
|
+
ledger: existingLedger,
|
|
739
|
+
capabilityRouting: lanePaths.capabilityRouting,
|
|
740
|
+
});
|
|
741
|
+
writeAssignmentSnapshot(waveAssignmentsPath(lanePaths, wave.wave), capabilityAssignments, {
|
|
742
|
+
lane: lanePaths.lane,
|
|
743
|
+
wave: wave.wave,
|
|
744
|
+
});
|
|
745
|
+
writeDependencySnapshot(waveDependencySnapshotPath(lanePaths, wave.wave), dependencySnapshot, {
|
|
746
|
+
lane: lanePaths.lane,
|
|
747
|
+
wave: wave.wave,
|
|
748
|
+
});
|
|
749
|
+
writeDependencySnapshotMarkdown(
|
|
750
|
+
waveDependencySnapshotMarkdownPath(lanePaths, wave.wave),
|
|
751
|
+
dependencySnapshot,
|
|
752
|
+
);
|
|
753
|
+
const runtimeAssignments = wave.agents.map((agent) => ({
|
|
754
|
+
agentId: agent.agentId,
|
|
755
|
+
role: agent.executorResolved?.role || null,
|
|
756
|
+
initialExecutorId: agent.executorResolved?.initialExecutorId || null,
|
|
757
|
+
executorId: agent.executorResolved?.id || null,
|
|
758
|
+
profile: agent.executorResolved?.profile || null,
|
|
759
|
+
selectedBy: agent.executorResolved?.selectedBy || null,
|
|
760
|
+
retryPolicy: agent.executorResolved?.retryPolicy || null,
|
|
761
|
+
allowFallbackOnRetry: agent.executorResolved?.allowFallbackOnRetry !== false,
|
|
762
|
+
fallbacks: agent.executorResolved?.fallbacks || [],
|
|
763
|
+
fallbackUsed: agent.executorResolved?.fallbackUsed === true,
|
|
764
|
+
fallbackReason: agent.executorResolved?.fallbackReason || null,
|
|
765
|
+
executorHistory: agent.executorResolved?.executorHistory || [],
|
|
766
|
+
}));
|
|
767
|
+
const docsQueue = buildDocsQueue({
|
|
768
|
+
lane: lanePaths.lane,
|
|
769
|
+
wave,
|
|
770
|
+
summariesByAgentId,
|
|
771
|
+
sharedPlanDocs: lanePaths.sharedPlanDocs,
|
|
772
|
+
componentPromotions: wave.componentPromotions,
|
|
773
|
+
runtimeAssignments,
|
|
774
|
+
});
|
|
775
|
+
writeDocsQueue(waveDocsQueuePath(lanePaths, wave.wave), docsQueue);
|
|
776
|
+
const securitySummary = buildWaveSecuritySummary({
|
|
777
|
+
lanePaths,
|
|
778
|
+
wave,
|
|
779
|
+
attempt,
|
|
780
|
+
summariesByAgentId,
|
|
781
|
+
});
|
|
782
|
+
writeJsonArtifact(waveSecurityPath(lanePaths, wave.wave), securitySummary);
|
|
783
|
+
writeTextAtomic(
|
|
784
|
+
waveSecurityMarkdownPath(lanePaths, wave.wave),
|
|
785
|
+
`${renderWaveSecuritySummaryMarkdown(securitySummary)}\n`,
|
|
786
|
+
);
|
|
787
|
+
const integrationSummary = buildWaveIntegrationSummary({
|
|
788
|
+
lanePaths,
|
|
789
|
+
wave,
|
|
790
|
+
attempt,
|
|
791
|
+
coordinationState,
|
|
792
|
+
summariesByAgentId,
|
|
793
|
+
docsQueue,
|
|
794
|
+
runtimeAssignments,
|
|
795
|
+
agentRuns,
|
|
796
|
+
capabilityAssignments,
|
|
797
|
+
dependencySnapshot,
|
|
798
|
+
securitySummary,
|
|
799
|
+
});
|
|
800
|
+
writeJsonArtifact(waveIntegrationPath(lanePaths, wave.wave), integrationSummary);
|
|
801
|
+
writeTextAtomic(
|
|
802
|
+
waveIntegrationMarkdownPath(lanePaths, wave.wave),
|
|
803
|
+
`${renderIntegrationSummaryMarkdown(integrationSummary)}\n`,
|
|
804
|
+
);
|
|
805
|
+
const ledger = deriveWaveLedger({
|
|
806
|
+
lane: lanePaths.lane,
|
|
807
|
+
wave,
|
|
808
|
+
summariesByAgentId,
|
|
809
|
+
coordinationState,
|
|
810
|
+
integrationSummary,
|
|
811
|
+
docsQueue,
|
|
812
|
+
attempt,
|
|
813
|
+
contQaAgentId: lanePaths.contQaAgentId,
|
|
814
|
+
contEvalAgentId: lanePaths.contEvalAgentId,
|
|
815
|
+
integrationAgentId: lanePaths.integrationAgentId,
|
|
816
|
+
documentationAgentId: lanePaths.documentationAgentId,
|
|
817
|
+
benchmarkCatalogPath: lanePaths.laneProfile?.paths?.benchmarkCatalogPath,
|
|
818
|
+
capabilityAssignments,
|
|
819
|
+
dependencySnapshot,
|
|
820
|
+
});
|
|
821
|
+
writeWaveLedger(waveLedgerPath(lanePaths, wave.wave), ledger);
|
|
822
|
+
const inboxDir = waveInboxDir(lanePaths, wave.wave);
|
|
823
|
+
ensureDirectory(inboxDir);
|
|
824
|
+
const sharedSummary = compileSharedSummary({
|
|
825
|
+
wave,
|
|
826
|
+
state: coordinationState,
|
|
827
|
+
ledger,
|
|
828
|
+
integrationSummary,
|
|
829
|
+
capabilityAssignments,
|
|
830
|
+
dependencySnapshot,
|
|
831
|
+
});
|
|
832
|
+
const sharedSummaryPath = path.join(inboxDir, "shared-summary.md");
|
|
833
|
+
writeCompiledInbox(sharedSummaryPath, sharedSummary.text);
|
|
834
|
+
const inboxesByAgentId = {};
|
|
835
|
+
for (const agent of wave.agents) {
|
|
836
|
+
const inbox = compileAgentInbox({
|
|
837
|
+
wave,
|
|
838
|
+
agent,
|
|
839
|
+
state: coordinationState,
|
|
840
|
+
ledger,
|
|
841
|
+
docsQueue,
|
|
842
|
+
integrationSummary,
|
|
843
|
+
capabilityAssignments,
|
|
844
|
+
dependencySnapshot,
|
|
845
|
+
});
|
|
846
|
+
const inboxPath = path.join(inboxDir, `${agent.agentId}.md`);
|
|
847
|
+
writeCompiledInbox(inboxPath, inbox.text);
|
|
848
|
+
inboxesByAgentId[agent.agentId] = { path: inboxPath, text: inbox.text, truncated: inbox.truncated };
|
|
849
|
+
}
|
|
850
|
+
const boardText = renderCoordinationBoardProjection({
|
|
851
|
+
wave: wave.wave,
|
|
852
|
+
waveFile: wave.file,
|
|
853
|
+
agents: wave.agents,
|
|
854
|
+
state: coordinationState,
|
|
855
|
+
capabilityAssignments,
|
|
856
|
+
dependencySnapshot,
|
|
857
|
+
});
|
|
858
|
+
const responseMetrics = buildCoordinationResponseMetrics(coordinationState);
|
|
859
|
+
const messageBoardPath = path.join(lanePaths.messageboardsDir, `wave-${wave.wave}.md`);
|
|
860
|
+
writeCoordinationBoardProjection(messageBoardPath, {
|
|
861
|
+
wave: wave.wave,
|
|
862
|
+
waveFile: wave.file,
|
|
863
|
+
agents: wave.agents,
|
|
864
|
+
state: coordinationState,
|
|
865
|
+
capabilityAssignments,
|
|
866
|
+
dependencySnapshot,
|
|
867
|
+
});
|
|
868
|
+
return {
|
|
869
|
+
coordinationLogPath,
|
|
870
|
+
coordinationState,
|
|
871
|
+
clarificationTriage,
|
|
872
|
+
docsQueue,
|
|
873
|
+
capabilityAssignments,
|
|
874
|
+
dependencySnapshot,
|
|
875
|
+
securitySummary,
|
|
876
|
+
integrationSummary,
|
|
877
|
+
integrationMarkdownPath: waveIntegrationMarkdownPath(lanePaths, wave.wave),
|
|
878
|
+
securityMarkdownPath: waveSecurityMarkdownPath(lanePaths, wave.wave),
|
|
879
|
+
ledger,
|
|
880
|
+
responseMetrics,
|
|
881
|
+
sharedSummaryPath,
|
|
882
|
+
sharedSummaryText: sharedSummary.text,
|
|
883
|
+
inboxesByAgentId,
|
|
884
|
+
messageBoardPath,
|
|
885
|
+
messageBoardText: boardText,
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
export function applyDerivedStateToDashboard(dashboardState, derivedState) {
|
|
890
|
+
if (!dashboardState || !derivedState) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
dashboardState.helperAssignmentsOpen = (derivedState.capabilityAssignments || []).filter(
|
|
894
|
+
(assignment) => assignment.blocking,
|
|
895
|
+
).length;
|
|
896
|
+
dashboardState.inboundDependenciesOpen = (derivedState.dependencySnapshot?.openInbound || []).length;
|
|
897
|
+
dashboardState.outboundDependenciesOpen = (derivedState.dependencySnapshot?.openOutbound || []).length;
|
|
898
|
+
dashboardState.coordinationOpen = derivedState.coordinationState?.openRecords?.length || 0;
|
|
899
|
+
dashboardState.openClarifications =
|
|
900
|
+
(derivedState.coordinationState?.clarifications || []).filter((record) =>
|
|
901
|
+
isOpenCoordinationStatus(record.status),
|
|
902
|
+
).length;
|
|
903
|
+
dashboardState.openHumanEscalations =
|
|
904
|
+
derivedState.responseMetrics?.openHumanEscalationCount ||
|
|
905
|
+
(derivedState.coordinationState?.humanEscalations || []).filter((record) =>
|
|
906
|
+
isOpenCoordinationStatus(record.status),
|
|
907
|
+
).length;
|
|
908
|
+
dashboardState.oldestOpenCoordinationAgeMs =
|
|
909
|
+
derivedState.responseMetrics?.oldestOpenCoordinationAgeMs ?? null;
|
|
910
|
+
dashboardState.oldestUnackedRequestAgeMs =
|
|
911
|
+
derivedState.responseMetrics?.oldestUnackedRequestAgeMs ?? null;
|
|
912
|
+
dashboardState.overdueAckCount = derivedState.responseMetrics?.overdueAckCount || 0;
|
|
913
|
+
dashboardState.overdueClarificationCount =
|
|
914
|
+
derivedState.responseMetrics?.overdueClarificationCount || 0;
|
|
915
|
+
}
|